2008-10-16 199 views
83

是否可以在每個表的每個字段中搜索Oracle中的特定值?在特定值的所有表中搜索所有字段(Oracle)

在某些表格中有數百個包含數千行的表,所以我知道這可能需要很長時間才能查詢。但我唯一知道的是,我想查詢的字段值是1/22/2008P09RR8。 <

我試過使用下面的這條語句來根據我認爲應該命名的東西找到一個合適的列,但它沒有返回任何結果。

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

這個數據庫是完全沒有文件的,我不知道這個字段從哪裏被取消。

有什麼想法?

+0

我們能做到這一點使用單個查詢,而不是使用存儲過程? – Freakyuser 2013-12-23 07:37:29

+0

是的,可以在純SQL中完成。請參閱[** SQL在整個SCHEMA中搜索所有表中的所有列的值**](https://lalitkumarb.wordpress.com/2015/01/06/sql-to-search-for-a-價值在所有在整個架構中的所有列中) – 2016-03-30 10:25:18

+0

@LalitKumarB您列出的頁面不再可訪問。是否可以發佈一些信息作爲答案? – 2016-07-05 17:50:17

回答

68

報價:

我用下面 這一說法基礎上找到 什麼,我認爲它應該被命名爲適當的列,但它 返回任何結果嘗試*

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

列不是一個對象。如果你的意思是你希望列名要像「%機構DTN%」,你想查詢的是:

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

但是,如果「DTN」字符串只是您的部分猜測,這可能贏得」幫助。

順便問一下,'1/22/2008P09RR8'是一個直接從單個列中選擇的值,你有多確定?如果你根本不知道它來自哪裏,它可能是幾列的連接,或者某個函數的結果,或者是一個坐在嵌套表對象中的值。所以你可能在試圖檢查每一列的價值。你不能從任何客戶端應用程序顯示這個值開始,並試圖找出它正在使用什麼查詢來獲得它?

不管怎麼說,diciu的回答給出了一種生成SQL查詢的方法來檢查每個表的每一列的值。您還可以使用PL/SQL塊和動態SQL在一個SQL會話中完全完成類似的任務。這裏有一些匆忙編寫的代碼:

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; 
    /

有一些方法可以使它更高效。

在這種情況下,給定您正在查找的值,您可以清楚地排除任何NUMBER或DATE類型的列,這將減少查詢的數量。甚至可能將其限制爲類型爲'%CHAR%'的列。

而是每列一個查詢,你可以建立每桌一個這樣的查詢:

SELECT * FROM table1 
    WHERE column1 = 'value' 
    OR column2 = 'value' 
    OR column3 = 'value' 
    ... 
    ; 
1

我對SQL promprt沒有簡單的解決方案。 Howeve有很多像Toad和PL/SQL Developer這樣的工具,它們有一個GUI,用戶可以在其中輸入要搜索的字符串,它將返回找到該字符串的表/過程/對象。

7

是的,你可以和你的DBA會恨你會發現你釘你的鞋在地板上,因爲這會導致大量的I/O,並把數據庫的性能真是倒作爲緩存清洗。

select column_name from all_tab_columns c, user_all_tables u where c.table_name = u.table_name; 

作爲開始。

我會開始運行查詢,使用v$sessionv$sqlarea。這根據oracle版本進行更改。這將縮小這個空間,而不是一切。

5

我會做這樣的事情(生成所有你需要的選擇)。 以後可以養活他們在sqlplus:

echo "select table_name from user_tables;" | sqlplus -S user/pwd | grep -v "^--" | grep -v "TABLE_NAME" | grep "^[A-Z]" | while read sw; 
do echo "desc $sw" | sqlplus -S user/pwd | grep -v "\-\-\-\-\-\-" | awk -F' ' '{print $1}' | while read nw; 
do echo "select * from $sw where $nw='val'"; 
done; 
done; 

它產生:

select * from TBL1 where DESCRIPTION='val' 
select * from TBL1 where ='val' 
select * from TBL2 where Name='val' 
select * from TBL2 where LNG_ID='val' 

而且他們做的是 - 每個table_nameuser_tables獲得各領域(從DESC),並創建一個SELECT *從表中的字段等於'val'。

25

我對上述代碼做了一些修改,以使其工作更快,如果你只在一個所有者中搜索。 您只需更改3個變量v_owner,v_data_type和v_search_string以適合您正在搜索的內容。

SET SERVEROUTPUT ON SIZE 100000 

DECLARE 
    match_count INTEGER; 
-- Type the owner of the tables you are looking at 
    v_owner VARCHAR2(255) :='ENTER_USERNAME_HERE'; 

-- Type the data type you are look at (in CAPITAL) 
-- VARCHAR2, NUMBER, etc. 
    v_data_type VARCHAR2(255) :='VARCHAR2'; 

-- Type the string you are looking at 
    v_search_string VARCHAR2(4000) :='string to search here...'; 

BEGIN 
    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 '||t.column_name||' = :1' 
    INTO match_count 
    USING 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; 
/
5

這是另一個修改後的版本,它將比較一個較低的子字符串匹配。這在Oracle 11g中可用。

DECLARE 
    match_count INTEGER; 
-- Type the owner of the tables you are looking at 
    v_owner VARCHAR2(255) :='OWNER_NAME'; 

-- Type the data type you are look at (in CAPITAL) 
-- VARCHAR2, NUMBER, etc. 
    v_data_type VARCHAR2(255) :='VARCHAR2'; 

-- Type the string you are looking at 
    v_search_string VARCHAR2(4000) :='%lower-search-sub-string%'; 

BEGIN 
    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 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; 
/
2

程序搜索整個數據庫:

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;  

執行語句

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; 

樣品結果

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##[email protected]@DEPT##DEPTNO 
Process exited. 
Disconnecting from the database test. 
3

我修改洪水的腳本來爲每個表執行一次,而不是爲每一列每個表的執行速度更快。它需要Oracle 11g或更高版本。

set serveroutput on size 100000 

declare 
    v_match_count integer; 
    v_counter integer; 

    -- The owner of the tables to search through (case-sensitive) 
    v_owner varchar2(255) := 'OWNER_NAME'; 
    -- A string that is part of the data type(s) of the columns to search through (case-insensitive) 
    v_data_type varchar2(255) := 'CHAR'; 
    -- The string to be searched for (case-insensitive) 
    v_search_string varchar2(4000) := 'FIND_ME'; 

    -- Store the SQL to execute for each table in a CLOB to get around the 32767 byte max size for a VARCHAR2 in PL/SQL 
    v_sql clob := ''; 
begin 
    for cur_tables in (select owner, table_name from all_tables where owner = v_owner and table_name in 
         (select table_name from all_tab_columns where owner = all_tables.owner and data_type like '%' || upper(v_data_type) || '%') 
         order by table_name) loop 
     v_counter := 0; 
     v_sql := ''; 

     for cur_columns in (select column_name from all_tab_columns where 
          owner = v_owner and table_name = cur_tables.table_name and data_type like '%' || upper(v_data_type) || '%') loop 
      if v_counter > 0 then 
       v_sql := v_sql || ' or '; 
      end if; 
      v_sql := v_sql || 'upper(' || cur_columns.column_name || ') like ''%' || upper(v_search_string) || '%'''; 
      v_counter := v_counter + 1; 
     end loop; 

     v_sql := 'select count(*) from ' || cur_tables.table_name || ' where ' || v_sql; 

     execute immediate v_sql 
     into v_match_count; 

     if v_match_count > 0 then 
      dbms_output.put_line('Match in ' || cur_tables.owner || ': ' || cur_tables.table_name || ' - ' || v_match_count || ' records'); 
     end if; 
    end loop; 

    exception 
     when others then 
      dbms_output.put_line('Error when executing the following: ' || dbms_lob.substr(v_sql, 32600)); 
end; 
/
4

如果我們知道表和科拉姆的名字,但要找出時間串的數量在針對每個模式:

Declare 

owner VARCHAR2(1000); 
tbl VARCHAR2(1000); 
cnt number; 
ct number; 
str_sql varchar2(1000); 
reason varchar2(1000); 
x varchar2(1000):='%string_to_be_searched%'; 

cursor csr is select owner,table_name 
from all_tables where table_name ='table_name'; 

type rec1 is record (
ct VARCHAR2(1000)); 

type rec is record (
owner VARCHAR2(1000):='', 
table_name VARCHAR2(1000):=''); 

rec2 rec; 
rec3 rec1; 
begin 

for rec2 in csr loop 

--str_sql:= 'select count(*) from '||rec.owner||'.'||rec.table_name||' where CTV_REMARKS like '||chr(39)||x||chr(39); 
--dbms_output.put_line(str_sql); 
--execute immediate str_sql 

execute immediate 'select count(*) from '||rec2.owner||'.'||rec2.table_name||' where column_name like '||chr(39)||x||chr(39) 
into rec3; 
if rec3.ct <> 0 then 
dbms_output.put_line(rec2.owner||','||rec3.ct); 
else null; 
end if; 
end loop; 
end; 
6

我知道這是一個老話題。但我看到一個問題的評論,詢問是否可以在SQL而不是使用PL/SQL完成。所以想到發佈解決方案。

下面的演示是Search for a VALUE in all COLUMNS of all TABLES in an entire SCHEMA

  • 搜索一個CHARACTER類型

讓我們來看看該值KINGSCOTT架構。

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> 
  • 搜索一個數字類型

讓我們來看看該值20SCOTT架構。

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

--IT運行完成 - 沒有錯誤

SET SERVEROUTPUT ON SIZE 100000 

DECLARE 
    v_match_count  INTEGER; 
    v_counter   INTEGER; 




v_owner   VARCHAR2 (255) := 'VASOA'; 
v_search_string VARCHAR2 (4000) := '99999'; 
v_data_type  VARCHAR2 (255) := 'CHAR'; 
v_sql    CLOB := ''; 

BEGIN 
    FOR cur_tables 
     IN ( SELECT owner, table_name 
       FROM all_tables 
      WHERE  owner = v_owner 
        AND table_name IN (SELECT table_name 
             FROM all_tab_columns 
             WHERE  owner = all_tables.owner 
              AND data_type LIKE 
                 '%' 
                || UPPER (v_data_type) 
                || '%') 
      ORDER BY table_name) 
    LOOP 
     v_counter := 0; 
     v_sql := ''; 

     FOR cur_columns 
     IN (SELECT column_name, table_name 
       FROM all_tab_columns 
       WHERE  owner = v_owner 
        AND table_name = cur_tables.table_name 
        AND data_type LIKE '%' || UPPER (v_data_type) || '%') 
     LOOP 
     IF v_counter > 0 
     THEN 
      v_sql := v_sql || ' or '; 
     END IF; 

     IF cur_columns.column_name is not null 
     THEN 
      v_sql := 
        v_sql 
       || 'upper(' 
       || cur_columns.column_name 
       || ') =''' 
       || UPPER (v_search_string)||''''; 

      v_counter := v_counter + 1; 
     END IF; 

     END LOOP; 

     IF v_sql is null 
     THEN 
     v_sql := 
       'select count(*) from ' 
      || v_owner 
      || '.' 
      || cur_tables.table_name; 

     END IF; 

     IF v_sql is not null 
     THEN 
     v_sql := 
       'select count(*) from ' 
      || v_owner 
      || '.' 
      || cur_tables.table_name 
      || ' where ' 
      || v_sql; 
     END IF; 

     --v_sql := 'select count(*) from ' ||v_owner||'.'|| cur_tables.table_name ||' where '|| v_sql; 


     --dbms_output.put_line(v_sql); 
     --DBMS_OUTPUT.put_line (v_sql); 

     EXECUTE IMMEDIATE v_sql INTO v_match_count; 

     IF v_match_count > 0 
     THEN 
     DBMS_OUTPUT.put_line (v_sql); 
     dbms_output.put_line('Match in ' || cur_tables.owner || ': ' || cur_tables.table_name || ' - ' || v_match_count || ' records'); 
     END IF; 

    END LOOP; 
EXCEPTION 
    WHEN OTHERS 
    THEN 
     DBMS_OUTPUT.put_line (
      'Error when executing the following: ' 
     || DBMS_LOB.SUBSTR (v_sql, 32600)); 
END; 
/
0

修改代碼以搜索不區分大小寫使用LIKE查詢,而不是找到完全匹配項...

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

借用,從this Blog post略微增強和簡化以下簡單的SQL語句似乎做得很好:

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

我有以下問題爲@Lalit Kumars答案,

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 

的解決方案是:

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" 
/