Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle-Abfrage, um alle Vorkommen eines Zeichens in einer Zeichenfolge zu finden

Wenn Sie die Antwort von GolezTrol erweitern, können Sie reguläre Ausdrücke verwenden, um die Anzahl der rekursiven Abfragen, die Sie ausführen, erheblich zu reduzieren:

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

REGEXP_COUNT() gibt zurück, wie oft das Muster übereinstimmt, in diesem Fall die Anzahl von R existiert in SSSRNNSRSSR . Dadurch wird die Rekursionsebene auf die genaue Anzahl begrenzt, die Sie benötigen.

INSTR() sucht einfach nach dem Index von R in Ihrem String. level ist die Tiefe der Rekursion, aber in diesem Fall ist es auch die Ebene th Vorkommen der Zeichenfolge, da wir uns auf die Anzahl der erforderlichen Wiederholungen beschränkt haben.

Wenn die Zeichenfolge, die Sie auswählen möchten, komplizierter ist, können Sie reguläre Ausdrücke und REGEXP_INSTR() im Gegensatz zu INSTR() wählen, aber es wird langsamer (nicht viel) und es ist unnötig, wenn es nicht erforderlich ist.

Einfacher Benchmark wie gewünscht:

Die beiden CONNECT BY-Lösungen würden angeben, dass die Verwendung von REGEXP_COUNT bei einer Zeichenfolge dieser Größe 20 % schneller ist.

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

Die Pipeline-Tabellenfunktion ist etwas langsamer, obwohl es interessant wäre zu sehen, wie sie sich bei großen Strings mit vielen Übereinstimmungen verhält.

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