Rozszerzając odpowiedź GolezTrol możesz użyć wyrażeń regularnych, aby znacznie zmniejszyć liczbę wykonywanych zapytań rekurencyjnych:
select instr('SSSRNNSRSSR','R', 1, level)
from dual
connect by level <= regexp_count('SSSRNNSRSSR', 'R')
REGEXP_COUNT() zwraca liczbę dopasowań wzorca, w tym przypadku liczbę razy R
istnieje w SSSRNNSRSSR
. Ogranicza to poziom rekurencji do dokładnie takiej liczby, jakiej potrzebujesz.
INSTR() po prostu wyszukuje indeks R w Twoim łańcuchu. level
to głębokość rekurencji, ale w tym przypadku jest to również poziom tego wystąpienie ciągu, ponieważ ograniczyliśmy się do wymaganej liczby rekurencji.
Jeśli ciąg, który chcesz wybrać, jest bardziej skomplikowany, możesz użyć wyrażeń regularnych i REGEXP_INSTR() w przeciwieństwie do INSTR(), ale będzie to wolniejsze (niewiele) i jest niepotrzebne, chyba że jest to wymagane.
Prosty test porównawczy zgodnie z żądaniem:
Dwa rozwiązania CONNECT BY wskazują, że użycie REGEXP_COUNT jest o 20% szybsze w przypadku łańcucha o tym rozmiarze.
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
Funkcja tabeli potokowej jest nieco wolniejsza, chociaż byłoby interesujące zobaczyć, jak działa na dużych ciągach z dużą liczbą dopasowań.
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