Oracle
 sql >> Database >  >> RDS >> Oracle

Query Oracle per trovare tutte le occorrenze di un carattere in una stringa

Estendendo la risposta di GolezTrol puoi utilizzare le espressioni regolari per ridurre significativamente il numero di query ricorsive che fai:

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

REGEXP_COUNT() restituisce il numero di volte in cui il modello corrisponde, in questo caso il numero di volte R esiste in SSSRNNSRSSR . Questo limita il livello di ricorsione al numero esatto di cui hai bisogno.

INSTR() cerca semplicemente l'indice di R nella stringa. level è la profondità della ricorsione ma in questo caso è anche il livello esimo occorrenza della stringa poiché abbiamo limitato al numero di ricorsi richiesti.

Se la stringa che desideri selezionare è più complicata, puoi utilizzare le espressioni regolari e REGEXP_INSTR() anziché INSTR() ma sarà più lenta (non di molto) e non è necessaria a meno che non sia necessario.

Semplice benchmark come richiesto:

Le due soluzioni CONNECT BY indicherebbero che l'utilizzo di REGEXP_COUNT è il 20% più veloce su una stringa di queste dimensioni.

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

La funzione della tabella pipeline è un po' più lenta, anche se sarebbe interessante vedere come si comporta su stringhe di grandi dimensioni con molte corrispondenze.

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