Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Consulta Oracle para encontrar todas as ocorrências de um caractere em uma string


Estendendo a resposta do GolezTrol, você pode usar expressões regulares para reduzir significativamente o número de consultas recursivas que você faz:
 select instr('SSSRNNSRSSR','R', 1, level)
   from dual
connect by level <= regexp_count('SSSRNNSRSSR', 'R')

REGEXP_COUNT() retorna o número de vezes que o padrão corresponde, neste caso o número de vezes R existe em SSSRNNSRSSR . Isso limita o nível de recursão ao número exato que você precisa.

INSTR() simplesmente procura o índice de R em sua string. level é a profundidade da recursão, mas neste caso também é o nível th ocorrência da string, pois restringimos ao número de recursos necessários.

Se a string que você deseja escolher for mais complicada, você pode usar expressões regulares e REGEXP_INSTR() em vez de INSTR(), mas será mais lento (não muito) e é desnecessário, a menos que seja necessário.

Benchmark simples conforme solicitado:

As duas soluções CONNECT BY indicariam que usar REGEXP_COUNT é 20% mais rápido em uma string desse tamanho.
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

A função de tabela em pipeline é um pouco mais lenta, embora seja interessante ver como ela se comporta em grandes strings com muitas correspondências.
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