Search All Fields In All Tables For A Specific Value (Oracle)

前端 未结 16 2058
一整个雨季
一整个雨季 2020-11-22 01:05

Is it possible to search every field of every table for a particular value in Oracle?

There are hundreds of tables with thousands of rows in some tables so I know th

相关标签:
16条回答
  • 2020-11-22 01:42

    Modifying the code to search case-insensitively using a LIKE query instead of finding exact matches...

    DECLARE
      match_count INTEGER;
      -- Type the owner of the tables you want to search.
      v_owner VARCHAR2(255) :='USER';
      -- Type the data type you're looking for (in CAPS). Examples include: VARCHAR2, NUMBER, etc.
      v_data_type VARCHAR2(255) :='VARCHAR2';
      -- Type the string you are looking for.
      v_search_string VARCHAR2(4000) :='Test';
    BEGIN
      dbms_output.put_line( 'Starting the search...' );
      FOR t IN (SELECT table_name, column_name FROM all_tab_cols where owner=v_owner and data_type = v_data_type) LOOP
        EXECUTE IMMEDIATE 
        'SELECT COUNT(*) FROM '||t.table_name||' WHERE LOWER('||t.column_name||') LIKE :1'
        INTO match_count
        USING LOWER('%'||v_search_string||'%');
        IF match_count > 0 THEN
          dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
        END IF;
      END LOOP;
    END;
    
    0 讨论(0)
  • 2020-11-22 01:43

    Procedure to Search Entire Database:

        CREATE or REPLACE PROCEDURE SEARCH_DB(SEARCH_STR IN VARCHAR2, TAB_COL_RECS OUT VARCHAR2) IS
          match_count integer;
          qry_str varchar2(1000);
          CURSOR TAB_COL_CURSOR IS 
              SELECT TABLE_NAME,COLUMN_NAME,OWNER,DATA_TYPE FROM ALL_TAB_COLUMNS WHERE DATA_TYPE in ('NUMBER','VARCHAR2') AND OWNER='SCOTT';
              BEGIN  
                FOR TAB_COL_REC  IN TAB_COL_CURSOR
                LOOP
                  qry_str := 'SELECT COUNT(*) FROM '||TAB_COL_REC.OWNER||'.'||TAB_COL_REC.TABLE_NAME|| 
                  ' WHERE '||TAB_COL_REC.COLUMN_NAME;
                   IF TAB_COL_REC.DATA_TYPE = 'NUMBER' THEN
                          qry_str := qry_str||'='||SEARCH_STR; 
                   ELSE
                           qry_str := qry_str||' like '||SEARCH_STR; 
                   END IF;
                           --dbms_output.put_line( qry_str );
                    EXECUTE IMMEDIATE  qry_str  INTO match_count;
                    IF match_count > 0 THEN          
                       dbms_output.put_line( qry_str );
                      --dbms_output.put_line( TAB_COL_REC.TABLE_NAME ||' '||TAB_COL_REC.COLUMN_NAME ||' '||match_count);     
                        TAB_COL_RECS := TAB_COL_RECS||'@@'||TAB_COL_REC.TABLE_NAME||'##'||TAB_COL_REC.COLUMN_NAME;
                    END IF; 
              END LOOP;
         END SEARCH_DB;    
    

    Execute Statement

      DECLARE
        SEARCH_STR VARCHAR2(200);
        TAB_COL_RECS VARCHAR2(200);
        BEGIN
          SEARCH_STR := 10;
          SEARCH_DB(
            SEARCH_STR => SEARCH_STR,
            TAB_COL_RECS => TAB_COL_RECS
          );
         DBMS_OUTPUT.PUT_LINE('TAB_COL_RECS = ' || TAB_COL_RECS);
         END;
    

    Sample Results

    Connecting to the database test.
    SELECT COUNT(*) FROM SCOTT.EMP WHERE DEPTNO=10
    SELECT COUNT(*) FROM SCOTT.DEPT WHERE DEPTNO=10
    TAB_COL_RECS = @@EMP##DEPTNO@@DEPT##DEPTNO
    Process exited.
    Disconnecting from the database test.
    
    0 讨论(0)
  • 2020-11-22 01:46

    I know this is an old topic. But I see a comment to the question asking if it could be done in SQL rather than using PL/SQL. So thought to post a solution.

    The below demonstration is to Search for a VALUE in all COLUMNS of all TABLES in an entire SCHEMA:

    • Search a CHARACTER type

    Let's look for the value KING in SCOTT schema.

    SQL> variable val varchar2(10)
    SQL> exec :val := 'KING'
    
    PL/SQL procedure successfully completed.
    
    SQL> SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
      2    SUBSTR (table_name, 1, 14) "Table",
      3    SUBSTR (column_name, 1, 14) "Column"
      4  FROM cols,
      5    TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select '
      6    || column_name
      7    || ' from '
      8    || table_name
      9    || ' where upper('
     10    || column_name
     11    || ') like upper(''%'
     12    || :val
     13    || '%'')' ).extract ('ROWSET/ROW/*') ) ) t
     14  ORDER BY "Table"
     15  /
    
    Searchword  Table          Column
    ----------- -------------- --------------
    KING        EMP            ENAME
    
    SQL>
    
    • Search a NUMERIC type

    Let's look for the value 20 in SCOTT schema.

    SQL> variable val NUMBER
    SQL> exec :val := 20
    
    PL/SQL procedure successfully completed.
    
    SQL> SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
      2    SUBSTR (table_name, 1, 14) "Table",
      3    SUBSTR (column_name, 1, 14) "Column"
      4  FROM cols,
      5    TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select '
      6    || column_name
      7    || ' from '
      8    || table_name
      9    || ' where upper('
     10    || column_name
     11    || ') like upper(''%'
     12    || :val
     13    || '%'')' ).extract ('ROWSET/ROW/*') ) ) t
     14  ORDER BY "Table"
     15  /
    
    Searchword  Table          Column
    ----------- -------------- --------------
    20          DEPT           DEPTNO
    20          EMP            DEPTNO
    20          EMP            HIREDATE
    20          SALGRADE       HISAL
    20          SALGRADE       LOSAL
    
    SQL>
    
    0 讨论(0)
  • 2020-11-22 01:46

    I was having following issues for @Lalit Kumars answer,

    ORA-19202: Error occurred in XML processing
    ORA-00904: "SUCCESS": invalid identifier
    ORA-06512: at "SYS.DBMS_XMLGEN", line 288
    ORA-06512: at line 1
    19202. 00000 -  "Error occurred in XML processing%s"
    *Cause:    An error occurred when processing the XML function
    *Action:   Check the given error message and fix the appropriate problem
    

    Solution is:

    WITH  char_cols AS
      (SELECT /*+materialize */ table_name, column_name
       FROM   cols
       WHERE  data_type IN ('CHAR', 'VARCHAR2'))
    SELECT DISTINCT SUBSTR (:val, 1, 11) "Searchword",
           SUBSTR (table_name, 1, 14) "Table",
           SUBSTR (column_name, 1, 14) "Column"
    FROM   char_cols,
           TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select "'
           || column_name
           || '" from "'
           || table_name
           || '" where upper("'
           || column_name
           || '") like upper(''%'
           || :val
           || '%'')' ).extract ('ROWSET/ROW/*') ) ) t
    ORDER  BY "Table"
    / 
    
    0 讨论(0)
  • 2020-11-22 01:49

    Quote:

    I've tried using this statement below to find an appropriate column based on what I think it should be named but it returned no results.*

    SELECT * from dba_objects WHERE
    object_name like '%DTN%'
    

    A column isn't an object. If you mean that you expect the column name to be like '%DTN%', the query you want is:

    SELECT owner, table_name, column_name FROM all_tab_columns WHERE column_name LIKE '%DTN%';
    

    But if the 'DTN' string is just a guess on your part, that probably won't help.

    By the way, how certain are you that '1/22/2008P09RR8' is a value selected directly from a single column? If you don't know at all where it is coming from, it could be a concatenation of several columns, or the result of some function, or a value sitting in a nested table object. So you might be on a wild goose chase trying to check every column for that value. Can you not start with whatever client application is displaying this value and try to figure out what query it is using to obtain it?

    Anyway, diciu's answer gives one method of generating SQL queries to check every column of every table for the value. You can also do similar stuff entirely in one SQL session using a PL/SQL block and dynamic SQL. Here's some hastily-written code for that:

        SET SERVEROUTPUT ON SIZE 100000
    
        DECLARE
          match_count INTEGER;
        BEGIN
          FOR t IN (SELECT owner, table_name, column_name
                      FROM all_tab_columns
                      WHERE owner <> 'SYS' and data_type LIKE '%CHAR%') LOOP
    
            EXECUTE IMMEDIATE
              'SELECT COUNT(*) FROM ' || t.owner || '.' || t.table_name ||
              ' WHERE '||t.column_name||' = :1'
              INTO match_count
              USING '1/22/2008P09RR8';
    
            IF match_count > 0 THEN
              dbms_output.put_line( t.table_name ||' '||t.column_name||' '||match_count );
            END IF;
    
          END LOOP;
    
        END;
        /
    

    There are some ways you could make it more efficient too.

    In this case, given the value you are looking for, you can clearly eliminate any column that is of NUMBER or DATE type, which would reduce the number of queries. Maybe even restrict it to columns where type is like '%CHAR%'.

    Instead of one query per column, you could build one query per table like this:

    SELECT * FROM table1
      WHERE column1 = 'value'
         OR column2 = 'value'
         OR column3 = 'value'
         ...
         ;
    
    0 讨论(0)
  • 2020-11-22 01:53

    Borrowing, slightly enhancing and simplifying from this Blog post the following simple SQL statement seems to do the job quite well:

    SELECT DISTINCT (:val) "Search Value", TABLE_NAME "Table", COLUMN_NAME "Column"
    FROM cols,
         TABLE (XMLSEQUENCE (DBMS_XMLGEN.GETXMLTYPE(
           'SELECT "' || COLUMN_NAME || '" FROM "' || TABLE_NAME || '" WHERE UPPER("'
           || COLUMN_NAME || '") LIKE UPPER(''%' || :val || '%'')' ).EXTRACT ('ROWSET/ROW/*')))
    ORDER BY "Table";
    
    0 讨论(0)
提交回复
热议问题