Search All Fields in All Tables For a Specific Value (Oracle)

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

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'
...
;

Please tell me how can I find all the values in Oracle database if I don't know the specific schema\table\column?

Well, anything will take a long time if you want to scan all tables and all columns (unless it's a tiny schema as Scott's).

Anyway: you'll need dynamic SQL. Here's an example: I'm searching through all CHAR-like datatype columns in my own schema (line #8), looking for KING (line #15):

SQL> DECLARE
2 l_str VARCHAR2 (500);
3 l_cnt NUMBER := 0;
4 BEGIN
5 FOR cur_r IN (SELECT u.table_name, u.column_name
6 FROM user_tab_columns u JOIN user_tables t
7 ON u.table_name = t.table_name
8 WHERE u.data_type LIKE '%CHAR%')
9 LOOP
10 l_str :=
11 'SELECT COUNT(*) FROM '
12 || cur_r.table_name
13 || ' WHERE '
14 || cur_r.column_name
15 || ' like (''%KING%'')';
16
17 EXECUTE IMMEDIATE (l_str)
18 INTO l_cnt;
19
20 IF l_cnt > 0
21 THEN
22 DBMS_OUTPUT.put_line (l_cnt || ' : ' || cur_r.table_name);
23 END IF;
24 END LOOP;
25 END;
26 /
1 : TABLE22
1 : EMP

PL/SQL procedure successfully completed.

SQL>

The result says that KING appears in two tables (TABLE22 and EMP), once in each of them.

Find tables & columns that will have the specific data in oracle

You:

  • Do not consider the owner of the table in the dynamic query.
  • May need to quote the identifiers.
  • Can also filter on the data_length.

Like this:

DECLARE
match_count INTEGER;
v_owner VARCHAR2(255) := 'GWEB';
v_data_type VARCHAR2(255) := 'VARCHAR2';
v_search_string VARCHAR2(4000) :='tom@example.com';
BEGIN
FOR t IN (
SELECT table_name,
column_name
FROM all_tab_cols
WHERE owner = v_owner
AND data_type = v_data_type
AND data_length >= LENGTH(v_search_string)
)
LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*)'
|| ' FROM "'||v_owner||'"."'||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;
/

db<>fiddle here

Oracle Search all tables all columns for string

At a minimum, you need to query ALL_TAB_COLUMNS, not ALL_TABLES

DECLARE
match_count integer;
v_search_string varchar2(4000) := <<string you want to search for>>;
BEGIN
FOR t IN (SELECT owner, table_name, column_name FROM all_tab_columns) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.owner || '.' || 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.owner || '.' || t.table_name ||' '||t.column_name||' '||match_count );
END IF;
END LOOP;
END;
/

If you are looking for a string, however, you would almost certainly want to restrict yourself to looking for columns that could store a string. It wouldn't make sense, for example, to search a DATE column for a string. And unless you have a great deal of a priori knowledge about what a BLOB column contains and the ability to parse the BLOB column's binary formatting, it wouldn't make sense to search a BLOB column for a string. Given that, I suspect you want something more like

DECLARE
match_count integer;
v_search_string varchar2(4000) := <<string you want to search for>>;
BEGIN
FOR t IN (SELECT owner,
table_name,
column_name
FROM all_tab_columns
WHERE data_type in ('CHAR', 'VARCHAR2', 'NCHAR', 'NVARCHAR2',
'CLOB', 'NCLOB') )
LOOP
BEGIN
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.owner || '.' || 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.owner || '.' || t.table_name ||' '||t.column_name||' '||match_count );
END IF;
EXCEPTION
WHEN others THEN
dbms_output.put_line( 'Error encountered trying to read ' ||
t.column_name || ' from ' ||
t.owner || '.' || t.table_name );
END;
END LOOP;
END;
/

Of course, this is going to be insanely slow-- you'd full scan every table once for every string column in the table. With moderately large tables and a moderate number of string columns, that is likely to take quite a while.

Search value in all tables of database

Thanks for all! Previous script implemented very slowly.
I got my value with this script:

DECLARE
match_count integer;
v_search_string varchar2(4000) := 'advcgtfs000080000ict1mosqiomujrk';

BEGIN
FOR t IN (SELECT owner,
table_name,
column_name
FROM all_tab_columns
WHERE data_type in ('VARCHAR2') )
LOOP
BEGIN
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.owner || '.' || 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.owner || '.' || t.table_name ||' '||t.column_name||' '||match_count );
END IF;
EXCEPTION
WHEN others THEN
dbms_output.put_line( 'Error encountered trying to read ' ||
t.column_name || ' from ' ||
t.owner || '.' || t.table_name );
END;
END LOOP;
END;
/

Oracle - SQL to get data from all tables with specific column and value

I am not sure what is expected so answering as per my understanding as following:

  • Let's say we have a table ACCOUNT which has CUST_ID column as following:
SQL> SELECT OWNER, A.TABLE_NAME, COLUMN_NAME FROM
2 ALL_TAB_COLS A
3 WHERE
4 A.COLUMN_NAME = 'CUST_ID';

OWNER TABLE_NAME COLUMN_NAME
---------- -------------------- --------------------
TEJASH ACCOUNT CUST_ID

SQL> SELECT * FROM ACCOUNT;

ACC_NR SUM_ CUST_ID
---------- ---------- ----------
500 3400 100
  • Now, I want to search in all the tables (on which I have access) to find all the tables having a CUST_ID column with value 100 in it.
SQL> SELECT
2 table_name, COLUMN_NAME,
3 to_number(xmlquery('/ROWSET/ROW/C/text()'
4 passing xmltype(dbms_xmlgen.getxml(
5 'select count(1) as c '
6 || 'from "' || owner || '"."' || table_name || '" WHERE ' || COLUMN_NAME || '=''100'''))
7 returning content)) as cOUNT
8 FROM ALL_TAB_COLS A
9 WHERE A.COLUMN_NAME = 'CUST_ID';

TABLE_NAME COLUMN_NAME COUNT
-------------------- -------------------- ----------
ACCOUNT CUST_ID 1

Here, every table with the column CUST_ID will appear and COUNT column displays the number of records in that table with CUST_ID = 100

  • Now, let's add a column to another table and see the effect:
SQL> ALTER TABLE ACTIVE_USERS ADD CUST_ID VARCHAR2(100);

Table altered.

SQL> INSERT INTO ACTIVE_USERS VALUES (5,SYSDATE, SYSDATE, 200);

1 row created.

SQL> SELECT * FROM ACTIVE_USERS;

CUST_NUM START_DATE END_DATE CUST
---------- -------------------- -------------------- ----
########## 21-NOV-19 21-NOV-19 200
########## 21-NOV-19 21-NOV-19
########## 01-JAN-18 01-JAN-19
########## 01-JAN-18
########## 01-JAN-19 01-JUN-19
########## 01-JAN-17 01-MAR-19

6 rows selected.
  • Now, Again running our query to find the data from all the tables:
SQL> SELECT
2 table_name, COLUMN_NAME,
3 to_number(xmlquery('/ROWSET/ROW/C/text()'
4 passing xmltype(dbms_xmlgen.getxml(
5 'select count(1) as c '
6 || 'from "' || owner || '"."' || table_name || '" WHERE ' || COLUMN_NAME || '=''100'''))
7 returning content)) as cOUNT
8 FROM ALL_TAB_COLS A
9 WHERE A.COLUMN_NAME = 'CUST_ID';

TABLE_NAME COLUMN_NAME COUNT
-------------------- -------------------- ----------
ACCOUNT CUST_ID 1
ACTIVE_USERS CUST_ID 0

SQL>

And, It worked!!

  • Again adding more data to the ACTIVE_USERS table and see the result.
SQL> INSERT INTO ACTIVE_USERS VALUES (6,SYSDATE-1, SYSDATE, 100);

1 row created.

SQL> INSERT INTO ACTIVE_USERS VALUES (7,SYSDATE-2, SYSDATE, 100);

1 row created.

SQL> INSERT INTO ACTIVE_USERS VALUES (8,SYSDATE-3, SYSDATE, 100);

1 row created.

SQL> SELECT * FROM ACTIVE_USERS;

CUST_NUM START_DATE END_DATE CUST
---------- -------------------- -------------------- ----
########## 21-NOV-19 21-NOV-19 200
########## 20-NOV-19 21-NOV-19 100
########## 19-NOV-19 21-NOV-19 100
########## 18-NOV-19 21-NOV-19 100
########## 21-NOV-19 21-NOV-19
########## 01-JAN-18 01-JAN-19
########## 01-JAN-18
########## 01-JAN-19 01-JUN-19
########## 01-JAN-17 01-MAR-19

9 rows selected.
  • Let's check the result of our query now.
SQL> SELECT
2 table_name, COLUMN_NAME,
3 to_number(xmlquery('/ROWSET/ROW/C/text()'
4 passing xmltype(dbms_xmlgen.getxml(
5 'select count(1) as c '
6 || 'from "' || owner || '"."' || table_name || '" WHERE ' || COLUMN_NAME || '=''100'''))
7 returning content)) as cOUNT
8 FROM ALL_TAB_COLS A
9 WHERE A.COLUMN_NAME = 'CUST_ID';

TABLE_NAME COLUMN_NAME COUNT
-------------------- -------------------- ----------
ACCOUNT CUST_ID 1
ACTIVE_USERS CUST_ID 3

SQL>

Again, It worked !! :)

Cheers!!



Related Topics



Leave a reply



Submit