トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

2-1-10 文字列中の指定文字列の数

SQLパズル

ValTable
Val
---------
abbabbaab
ababaaaa
ab
a

文字列Val内の'ab'の数を取得する。

出力結果
Val        文字列abの数
---------  ------------
abbabbaab  3
ababaaaa   2
ab         1
a          0


データ作成スクリプト

create table ValTable(Val) as
select 'abbabbaab' from dual union
select 'ababaaaa' from dual union
select 'ab' from dual union
select 'a'  from dual;


SQL

--■■■Length関数を使う方法■■■
select val,
(Length(val)-nvl(Length(replace(val,'ab')),0))/Length('ab') as "文字列abの数"
from ValTable
order by val desc;

--■■■model句で再帰的にinstr関数かRegExp_Instr関数を使う方法1■■■
select Val,cnt as "文字列abの数"
  from ValTable
 model
 partition by (RowNum as PID)
 dimension by (0 as soeji)
 measures(Val,0 as hitPos,0 as cnt,1 as startPos)
 rules iterate (100) (hitPos[0] = instr(Val[0],'ab',startPos[0]),
                      cnt[0] = case when hitPos[0] = 0
                                    then cnt[0]
                                    else cnt[0]+1 end,
                      startPos[0] = case when hitPos[0] = 0
                                    then startPos[0]
                                    else hitPos[0]+1 end)
order by Val desc;

--■■■model句で再帰的にinstr関数かRegExp_Instr関数を使う方法2■■■
select Val,hitCnt as "文字列abの数"
  from ValTable
 model
 partition by (RowNum as PID)
 dimension by (0 as soeji)
 measures(Val,0 as hitCnt)
 rules iterate (100)
 (hitCnt[0] = case when instr(Val[0],'ab',1,iteration_number+1) = 0
                   then hitCnt[0] else iteration_number+1 end)
order by Val desc;


解説

replace関数でabを消去する前と後の文字列長の差を、abの文字列長で割って、
文字列abの数を取得してます。

11gならRegexp_Countが使えます。
REGEXP_COUNT - オラクル・Oracle SQL 関数リファレンス

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
PL/SQLならowa_patternを使ってもいいでしょう。
10-215 owa_patternで正規表現

SQL> declare
  2      wk ValTable.Val%type;
  3      willOut varchar2(4000);
  4  begin
  5      for rec in (select Val from ValTable) Loop
  6          wk := rec.Val;
  7          willOut := rec.Val || 'のabの数は';
  8          willOut := willOut || OWA_PATTERN.CHANGE(wk,'ab',null,'g');
  9          DBMS_Output.Put_Line(willOut);
 10      end Loop;
 11  end;
 12  /
aのabの数は0
abのabの数は1
ababaaaaのabの数は2
abbabbaabのabの数は3

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
model句で再帰的にinstr関数かRegExp_Instr関数を使う方法の1と2は、
数える文字列がaaaa,abab,acccacなどの場合に、
文字列の登場回数の数え方を理解した上で、使い分けるといいでしょう。

select instr('aaaa','aa',1,1) as a1,
       instr('aaaa','aa',1,2) as a2,
       instr('aaaa','aa',1,3) as a3,
       instr('aaaa','aa',1,4) as a4,
       instr('aaaa','aa',1,5) as a5,
       instr('aaaa','aa',1,6) as a6
from dual ;

A1  A2  A3  A4  A5  A6
--  --  --  --  --  --
 1   2   3   0   0   0