sql >> Base de Datos >  >> RDS >> Oracle

Consulta de Oracle para encontrar todas las apariciones de un carácter en una cadena

Al extender la respuesta de GolezTrol, puede usar expresiones regulares para reducir significativamente la cantidad de consultas recursivas que realiza:

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

REGEXP_COUNT() devuelve el número de veces que coincide el patrón, en este caso el número de veces R existe en SSSRNNSRSSR . Esto limita el nivel de recursividad al número exacto que necesita.

INSTR() simplemente busca el índice de R en su cadena. level es la profundidad de la recursividad pero en este caso también es el nivel th ocurrencia de la cadena ya que restringimos el número de recurses requerido.

Si la cadena que desea seleccionar es más complicada, puede optar por expresiones regulares y REGEXP_INSTR() en lugar de INSTR(), pero será más lento (no mucho) y es innecesario a menos que sea necesario.

Punto de referencia simple según lo solicitado:

Las dos soluciones CONNECT BY indicarían que usar REGEXP_COUNT es un 20 % más rápido en una cadena de este tamaño.

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 función de tabla canalizada es un poco más lenta, aunque sería interesante ver cómo funciona en cadenas grandes con muchas coincidencias.

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