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

SQL select para todos os registros que podem conter um valor específico


Então, você deseja fazer uma pesquisa de texto livre semelhante ao Google em seu banco de dados. Isso pode ser feito, mas o desempenho será Teh Suck! O Google é rápido porque possui índices em seus índices, armazenamentos de dados duplicados e geralmente otimiza tudo exatamente para esse tipo de pesquisa.

De qualquer forma, aqui está uma prova de conceito usando SQL dinâmico e o dicionário de dados Oracle. Observe que restrinjo as colunas ao tipo de dados que desejo pesquisar, ou seja, strings.
SQL> set serveroutput on size unlimited
SQL> declare
  2      dummy varchar2(1);
  3  begin
  4      for r in ( select table_name, column_name from user_tab_cols
  5                 where data_type in ('VARCHAR2', 'CHAR', 'CLOB') )
  6      loop
  7          begin
  8              execute immediate 'select null from '||r.table_name
  9                      ||' where '||r.column_name||' like ''%&search_value%'' '
 10                      ||' and rownum = 1'
 11                 into dummy;
 12              dbms_output.put_line('Found it in >>>'
 13                     ||r.table_name||'.'||r.column_name);
 14          exception
 15              when others then
 16                  -- bad practice ahoy!
 17                  null;
 18          end;
 19      end loop;
 20  end;
 21  /
Enter value for search_value: MAISIE
old   9:                ||' where '||r.column_name||' like ''%&search_value%'' '
new   9:                ||' where '||r.column_name||' like ''%MAISIE%'' '
Found it in >>>T23.NAME

PL/SQL procedure successfully completed.

SQL>

Uma implementação mais robusta pode precisar lidar com maiúsculas e minúsculas, palavras inteiras etc. Se você estiver em 10g ou superior, as expressões regulares podem ser úteis, mas combinar regex e SQL dinâmico é, er, interessante perspectiva.

Repito que o desempenho vai ser Teh Suck! em um grande conjunto de dados. É virtualmente impossível sintonizar, porque não podemos indexar todas as colunas e certamente não suportar LIKE ou correspondências difusas semelhantes. Uma abordagem alternativa seria usar XQuery para gerar uma representação XML de seus dados e depois usar Text para indexá-los. Manter esse repositório seria uma sobrecarga, mas o esforço seria um bom investimento se você precisar dessa funcionalidade regularmente, especialmente em um ambiente de produção.

Podemos realizar uma pesquisa mais ampla em todas as tabelas nas quais temos privilégios usando all_tab_cols em vez de.
for r in ( select owner, table_name, column_name from all_tab_cols
                   where data_type in ('VARCHAR2', 'CHAR', 'CLOB') )

Obviamente, precisamos prefixar o esquema proprietário na instrução gerada.
execute immediate 'select null from '||r.owner||'.'||r.table_name
                       ||' where '||r.column_name||' like ''%