Oracle
 sql >> Base de données >  >> RDS >> Oracle

Requête Oracle pour trouver toutes les occurrences d'un caractère dans une chaîne

En étendant la réponse de GolezTrol, vous pouvez utiliser des expressions régulières pour réduire considérablement le nombre de requêtes récursives que vous effectuez :

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

REGEXP_COUNT() renvoie le nombre de fois que le modèle correspond, dans ce cas le nombre de fois R existe dans SSSRNNSRSSR . Cela limite le niveau de récursivité au nombre exact dont vous avez besoin.

INSTR() recherche simplement l'index de R dans votre chaîne. level est la profondeur de la récursivité mais dans ce cas c'est aussi le niveau th occurrence de la chaîne car nous avons limité le nombre de récursions requis.

Si la chaîne que vous voulez choisir est plus compliquée, vous pouvez opter pour des expressions régulières et REGEXP_INSTR() par opposition à INSTR() mais ce sera plus lent (pas beaucoup) et c'est inutile sauf si nécessaire.

Benchmark simple comme demandé :

Les deux solutions CONNECT BY indiqueraient que l'utilisation de REGEXP_COUNT est 20 % plus rapide sur une chaîne de cette taille.

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 fonction de table en pipeline est un peu plus lente, mais il serait intéressant de voir comment elle fonctionne sur de grandes chaînes avec beaucoup de correspondances.

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