6

文字列内の文字の出現箇所をすべて見つけるには、toad で Oracle クエリを作成する必要があります。たとえばR、文字列SSSRNNSRSSRで を検索している場合、位置 4、8、および 11 が返されます。

私はOracleを初めて使用し、これを試しました。

select instr(mtr_ctrl_flags, 'R', pos + 1, 1) as pos1 
  from mer_trans_reject  
 where pos in ( select instr(mtr_ctrl_flags, 'R', 1, 1) as pos 
                  from mer_trans_reject
                       );

mtr_ctrl_flags列名です。pos無効な識別子であることを示すエラーが表示されます。

4

3 に答える 3

14

GolezTrol の回答を拡張すると、正規表現を使用して、実行する再帰クエリの数を大幅に減らすことができます。

 select instr('SSSRNNSRSSR','R', 1, level)
   from dual
connect by level <= regexp_count('SSSRNNSRSSR', 'R')

REGEXP_COUNT()は、パターンが一致した回数を返します。この場合、 にR存在する回数ですSSSRNNSRSSR。これにより、再帰のレベルが必要な正確な数に制限されます。

INSTR()は、文字列内の R のインデックスを検索するだけです。levelは再帰の深さですが、この場合、必要な再帰の数に制限されているため、文字列の level番目のオカレンスでもあります。

選択したい文字列がより複雑な場合は、INSTR() ではなく、正規表現 ans REGEXP_INSTR()を使用できますが、遅くなり (それほどではありません)、必要でない限り不要です。


要求に応じた簡単なベンチマーク:

2 つの CONNECT BY ソリューションは、このサイズの文字列で REGEXP_COUNT を使用する方が 20% 高速であることを示しています。

SQL> set timing on
SQL>
SQL> -- CONNECT BY with REGEX
SQL> declare
  2     type t__num is table of number index by binary_integer;
  3     t_num t__num;
  4  begin
  5    for i in 1 .. 100000 loop
  6       select instr('SSSRNNSRSSR','R', 1, level)
  7         bulk collect into t_num
  8         from dual
  9      connect by level <= regexp_count('SSSRNNSRSSR', 'R')
 10              ;
 11     end loop;
 12  end;
 13  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:03.94
SQL>
SQL> -- CONNECT BY with filter
SQL> declare
  2     type t__num is table of number index by binary_integer;
  3     t_num t__num;
  4  begin
  5    for i in 1 .. 100000 loop
  6       select pos
  7         bulk collect into t_num
  8         from ( select substr('SSSRNNSRSSR', level, 1) as character
  9                     , level as pos
 10                  from dual t
 11               connect by level <= length('SSSRNNSRSSR') )
 12        where character = 'R'
 13              ;
 14     end loop;
 15  end;
 16  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.80

パイプライン化されたテーブル関数はかなり遅くなりますが、多くの一致がある大きな文字列に対してどのように機能するかを見るのは興味深いでしょう.

SQL> -- PIPELINED TABLE FUNCTION
SQL> declare
  2     type t__num is table of number index by binary_integer;
  3     t_num t__num;
  4  begin
  5    for i in 1 .. 100000 loop
  6       select *
  7         bulk collect into t_num
  8         from table(string_indexes('SSSRNNSRSSR','R'))
  9              ;
 10     end loop;
 11  end;
 12  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:06.54
于 2013-07-28T08:51:10.353 に答える
9

これは解決策です:

select
  pos
from
  (select
    substr('SSSRNNSRSSR', level, 1) as character,
    level as pos
  from
    dual
  connect by
    level <= length(t.text))
where
  character = 'R'

dual単一の行を返す組み込みのテーブルです。とても便利!

connect by再帰クエリを作成できます。これは、ツリー状のデータ (親子関係) からリストを生成するためによく使用されます。これにより、その前のクエリを多かれ少なかれ繰り返すことができます。levelそして、再帰がどれだけ深く進んだかを確認できるような、特別なフィールドがあります。

この場合、これを使用して文字列を文字に分割し、各文字の行を返します。を使用levelすると、クエリを繰り返し、文字列の末尾に到達するまで文字を取得できます。

pos次に、その文字を含むすべての行に対してを返すだけです'R'

于 2013-07-28T08:17:24.680 に答える
4

ここでa_horse_with_no_name の課題を取り上げるのは、パイプライン化されたテーブル関数を使用した別の回答です。

パイプライン化された関数は、通常どおりクエリできる配列を返します。多数の一致がある文字列に対して、これは再帰クエリよりも優れたパフォーマンスを発揮すると予想されますが、すべての場合と同様に、最初に自分でテストしてください。

create type num_array as table of number
/


create function string_indexes (
    PSource_String in varchar2
  , PSearch_String in varchar2
    ) return num_array pipelined is

begin

   for i in 1 .. length(PSource_String) loop

      if substr(PSource_String, i, 1) = PSearch_String then
         pipe row(i);
      end if;

   end loop;

   return;

end;
/

次に、それにアクセスするには:

select *
  from table(string_indexes('SSSRNNSRSSR','R'))

SQL フィドル

于 2013-07-28T09:48:46.560 に答える