搜索特定值的所有表中的所有字段(Oracle)

Chr*_*way 110 sql oracle search plsql database-table

是否有可能在每个表的每个字段中搜索Oracle中的特定值?

在一些表中有数百个表有数千行,所以我知道这可能需要很长时间才能查询.但我唯一知道的是我想要查询的字段的值是1/22/2008P09RR8.<

我已经尝试使用下面的这个语句根据我认为应该命名的内容找到一个合适的列,但它没有返回任何结果.

SELECT * from dba_objects 
WHERE object_name like '%DTN%'
Run Code Online (Sandbox Code Playgroud)

这个数据库绝对没有文档,我不知道该字段的来源.

有什么想法吗?

Dav*_*sta 87

引用:

我已经尝试使用下面的这个语句根据我认为应该命名的内容找到一个合适的列,但它没有返回任何结果.*

SELECT * from dba_objects WHERE
object_name like '%DTN%'
Run Code Online (Sandbox Code Playgroud)

列不是对象.如果您的意思是您希望列名称与'%DTN%'相似,那么您想要的查询是:

SELECT owner, table_name, column_name FROM all_tab_columns WHERE column_name LIKE '%DTN%';
Run Code Online (Sandbox Code Playgroud)

但是,如果"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;
    /
Run Code Online (Sandbox Code Playgroud)

有一些方法可以使它更有效率.

在这种情况下,给定您要查找的值,您可以清楚地删除任何NUMBER或DATE类型的列,这将减少查询的数量.甚至可能将其限制为类型为'%CHAR%'的列.

您可以为每个表构建一个查询,而不是每列一个查询,如下所示:

SELECT * FROM table1
  WHERE column1 = 'value'
     OR column2 = 'value'
     OR column3 = 'value'
     ...
     ;
Run Code Online (Sandbox Code Playgroud)

  • @ammoQ - 就像我在倒数第二段中所说的那样? (7认同)

Flo*_*ood 32

我对上面的代码做了一些修改,如果你只搜索一个所有者,它可以更快地工作.您只需更改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;
/
Run Code Online (Sandbox Code Playgroud)

  • 我需要在表名/列名周围加上双引号,以避免需要引用时出现问题: `'SELECT COUNT(*) FROM "'||t.table_name||'" WHERE "'||t.column_name ||'" = :1'` (2认同)

jim*_*jim 7

是的,你可以和你的DBA讨厌你,并且会发现你将你的鞋子钉在地板上,因为这会导致大量的I/O并且在缓存清除时真正降低数据库性能.

select column_name from all_tab_columns c, user_all_tables u where c.table_name = u.table_name;
Run Code Online (Sandbox Code Playgroud)

作为一个开始.

我将从运行的查询开始,使用v$sessionv$sqlarea.这基于oracle版本而变化.这将缩小空间范围,而不是打击一切.


Lal*_*r B 7

我知道这是一个古老的话题.但是我看到一个问题的评论,询问是否可以用SQL而不是用PL/SQL.所以想发布一个解决方案.

以下演示是在整个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>
Run Code Online (Sandbox Code Playgroud)
  • 搜索NUMERIC类型

让我们来看看该值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>
Run Code Online (Sandbox Code Playgroud)

  • hrmm ....使用xml看起来像矫枉过正.除此之外:`XML处理错误ORA-00932:数据类型不一致:预期NUMBER得到了BLOB` (6认同)
  • ORA-19202:XML处理错误ORA-00932:数据类型不一致:预期CHAR得到BLOB ORA-06512:在"SYS.DBMS_XMLGEN",第288行ORA-06512:第1行19202. 00000 - "XML处理出错%s"*原因:处理XML函数时发生错误*操作:检查给定的错误消息并修复相应的问题 (2认同)

小智 6

这是另一个修改版本,它将比较较低的子字符串匹配.这适用于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;
/
Run Code Online (Sandbox Code Playgroud)


dic*_*ciu 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;
Run Code Online (Sandbox Code Playgroud)

它产生:

select * from TBL1 where DESCRIPTION='val'
select * from TBL1 where ='val'
select * from TBL2 where Name='val'
select * from TBL2 where LNG_ID='val'
Run Code Online (Sandbox Code Playgroud)

而他们做的是-每个table_nameuser_tables获得的每个字段(从DESC),并从表中创建一个选择*,其中字段等于"VAL".


Mik*_*dey 5

我将 Flood 的脚本修改为对每个表执行一次,而不是对每个表的每一列执行一次,以加快执行速度。它需要 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;
/
Run Code Online (Sandbox Code Playgroud)


小智 5

如果我们知道表名和列名,但想找出每个模式中字符串出现的次数:

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;
Run Code Online (Sandbox Code Playgroud)


bek*_*kur 5

对于@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
Run Code Online (Sandbox Code Playgroud)

解决办法是:

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"
/ 
Run Code Online (Sandbox Code Playgroud)