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

Sélection SQL pour tous les enregistrements pouvant contenir une valeur spécifique

Donc, vous voulez faire une recherche de texte libre de type Google sur votre base de données. Cela peut être fait mais la performance sera Teh Suck! Google est rapide car il a des index sur ses index, des magasins de données en double et optimise généralement tout pour précisément ce type de recherche.

Quoi qu'il en soit, voici une preuve de concept utilisant SQL dynamique et le dictionnaire de données Oracle. Notez que je limite les colonnes au type de données que je souhaite rechercher, c'est-à-dire des chaînes.

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>

Une implémentation plus robuste peut avoir besoin de gérer la casse, les mots entiers, etc. Si vous utilisez 10g ou plus, les expressions régulières peuvent être utiles, mais combiner regex et SQL dynamique est un, euh, intéressant prospect.

Je répète que la performance va être Teh Suck ! sur un grand ensemble de données. Il est pratiquement impossible de régler, car nous ne pouvons pas indexer chaque colonne, et certainement pas pour prendre en charge LIKE ou des correspondances floues similaires. Une approche alternative consisterait à utiliser XQuery pour générer une représentation XML de vos données, puis à utiliser Text pour l'indexer. La maintenance d'un tel référentiel serait une surcharge, mais l'effort serait un bon investissement si vous avez besoin de cette fonctionnalité de manière régulière, en particulier dans un environnement de production.

Nous pouvons effectuer une recherche plus large dans toutes les tables sur lesquelles nous avons des privilèges en utilisant all_tab_cols Au lieu.

for r in ( select owner, table_name, column_name from all_tab_cols
                   where data_type in ('VARCHAR2', 'CHAR', 'CLOB') )

Évidemment, nous devons préfixer le schéma propriétaire dans la déclaration générée.

execute immediate 'select null from '||r.owner||'.'||r.table_name
                       ||' where '||r.column_name||' like ''%