Muniqsoft Training

Auswahl  

Suche Datensatz in einem Schema 

Oracle
PL/SQL
12.1, 12.2
12.12.18 (MP)
12.12.18 (MP)
PL/SQL

Body

Hatten Sie auch schon einmal das Problem, dass Sie einen Datensatz gesucht haben, aber nicht wussten, in welcher Spalte dieser steht? Wir haben noch eines drauf gesetzt und können sogar Werte suchen, von denen man nicht weiß, in welcher Tabelle sie stehen. Diese Fragestellung kann auftreten, wenn man mit einer Applikation arbeitet, deren genaues Datenbank-Layout nicht bekannt ist.

Es sollte jedoch erwähnt werden, dass hier mehrfach ein Full-Tablescan erzeugt wird, der bei einer großen Tabellenanzahl zu einer SEHR GROSSEN Performance-Belastung führen kann. Besonders die Option ALL wird sehr viel Ressourcen verbrauchen, deswegen sollte man die Procedure nur auf Test-Maschinen absetzen.

Vorbereitung

In dieser Procedure werden zwei Data-Dictionary Tabellen (dba_objects und dba_tab_columns) benutzt. Leider sind Rechte an DD-Objekten über Rollen an die Benutzer vergeben, die wiederum in PL/SQL nicht verwendet werden können.

Drei Möglichkeiten stehen als Problemlösung zur Verfügung:

  • Sie kompilieren die Procedure als Benutzer SYS, denn der hat alle Rechte. :-)
  • Sie vergeben die beiden Rechte DIREKT an den Benutzer, der dann die Procedure kompiliert:
GRANT SELECT on dba_tab_columns TO system;
GRANT SELECT on dba_objects TO system;
  • Sie schreiben die Procedure in einen anonymen Block um. Ersetzen Sie den Bereich "CREATE OR REPLACE bis "IS" durch:
ACCEPT v_schema_name PROMPT "Schema eingeben (ALL für Alle): "
ACCEPT v_search_string PROMPT "Suchstring eingeben (Bsp: Hallo%): "
ACCEPT v_table_name "Tabellennamen eingeben (Leer = alle Tabellen): "
ACCEPT v_type "Datentyp STRING oder NUMBER eingeben: "

DECLARE
  p_schema_name VARCHAR2(30):=upper('&&v_schema_name');
  p_search_string VARCHAR2(30):='&&v_search_string';
  p_table_name VARCHAR2(30):=upper('&&v_table_name');
  p_type VARCHAR2(30):='&&v_type';
     
TYPE ref_curs ...
 

Folgende Parameter können übergeben werden:

  • p_search_string
    Nimmt den gesuchten String auf. Folgende Möglichkeiten stehen zur Verfügung:
    "STRING", "%STRING" oder "%STRING%"
  • p_schema_name
    Name des Schema, in dem gesucht werden soll. Default ist das aktuelle. Mit der Option ALL werden alle Schematas durchsucht. Ausgeschlossen sind die Schematas von SYS, SYSTEM und allen SYS-nahen Benutzern
  • p_table_name
    Hier kann optiomal der Tabellenname angegebn werden, dann werden nur deren Spalten durchsucht.
  • p_type
    Wenn es sich um eine String Spalte (char, varchar2,clob) handelt, wo der gesuchte Wert enthalten ist, können Sie hier die Option 'STRING' angeben. Die Option 'NUMBER' durchsucht nummerische Spalten.

Procedure:

 
CREATE OR REPLACE PROCEDURE find_in_tables
   (p_search_string IN VARCHAR2,
    p_schema_name   IN VARCHAR2 DEFAULT NULL,                              
    p_table_name    IN VARCHAR2 DEFAULT NULL,
    p_type IN VARCHAR2 DEFAULT 'STRING')
   uthid current_user

 IS
  TYPE ref_curs_type IS REF CURSOR;
  refc   ref_curs_type;
  sql_str    VARCHAR2(200);
  row_ret    ROWID;
  v_user VARCHAR2(30);

BEGIN
  /* Wenn Benutzer NULL ist wir aktueller Benutzer verwendet */
  SELECT sys_context('USERENV', 'SESSION_USER') INTO v_user FROM dual;
  v_user := nvl(p_schema_name, v_user);
  dbms_output.put_line
   ('Suche wurde ausgeführt mit: User='||v_user||' Table='||p_table_name);
  FOR rec IN (select do.owner,table_name, column_name, data_type
                FROM sys.dba_tab_columns dtc, dba_objects do
               WHERE dtc.table_name = do.object_name
                 and do.object_type = 'TABLE'
                 and dtc.owner = decode(v_user,'ALL',dtc.owner,v_user)
                 and dtc.owner not in ('SYS','SYSTEM','OUTLN','SYSMAN',
                                       'MDSYS','ORDSYS','WMSYS','CTXSYS',
                                       'OLAPSYS')
                 and do.object_name = nvl(p_table_name, do.object_name)) LOOP
    IF upper(p_type) = 'STRING' AND
       (rec.data_type = 'CHAR' OR rec.data_type = 'VARCHAR2' or
        rec.data_type = 'CLOB') THEN
      sql_str := 'SELECT rowid FROM ' || rec.owner || '.' ||
      rec.table_name ||' WHERE ' || rec.column_name || ' like ' ||
      chr(39) || p_search_string || chr(39);
   
      BEGIN
       
        OPEN refc FOR sql_str;
        LOOP
          FETCH refc
            INTO row_ret;
          EXIT WHEN refc%NOTFOUND;
          dbms_output.put_line('Owner='||rec.owner||' Table=' ||
          rec.table_name || ' Col=' ||rec.column_name || ' Rowid=' ||
          row_ret);
       
        END LOOP;
        row_ret := null;
        CLOSE refc;
      EXCEPTION
        WHEN OTHERS THEN
          IF v_user<>'ALL' THEN
           dbms_output.put_line('Fehler in Table=' || rec.table_name);
          END IF;
       
      END;
   
    ELSIF p_type = 'Number' and rec.data_type = 'NUMBER' THEN
      sql_str := 'SELECT rowid FROM ' || p_schema_name || '.' ||
      rec.table_name || ' WHERE ' || rec.column_name || '='
      || p_search_string;
      BEGIN
        OPEN refc FOR sql_str;
        LOOP
          FETCH refc
            INTO row_ret;
          EXIT WHEN refc%NOTFOUND;
          dbms_output.put_line('Owner='||rec.owner||' Table=' ||
          rec.table_name || ' Col=' ||rec.column_name || ' Rowid='
          || row_ret);
       
        END LOOP;
        row_ret := null;
        CLOSE refc;
      EXCEPTION
        WHEN OTHERS THEN
          IF v_user<>'ALL' THEN
          dbms_output.put_line('Fehler in Table=' || rec.table_name);
          END IF;
      END;
   
    END IF;
 
  END LOOP;
END;
/
 

Beispielaufrufe:

SQL> EXEC find_in_tables ('PRESI%','SCOTT','EMP');

Ausgabe: Table=EMP Col=JOB Rowid=AAANOxAAEAAAAAdAAI

SQL> EXEC find_in_tables ('DALL%','ALL');

Ausgabe: Table=DEPT Col=LOC Rowid=AAANOvAAEAAAAANAAB

Besuchen Sie uns doch bei einer unsere über 40 Oracle Schulungen in München - Unterhaching.