Suche Alle Felder in allen Tabellen für einen bestimmten Wert (Oracle)
-
03-07-2019 - |
Frage
Ist es möglich, jedes Feld jeder Tabelle für einen bestimmten Wert in Oracle suchen?
Es gibt Hunderte von Tabellen mit Tausenden von Zeilen in einigen Tabellen so weiß ich, das eine sehr lange Zeit zu fragen nehmen konnte. Aber das einzige, was ich weiß, ist, dass ein Wert für das Feld würde ich gegen 1/22/2008P09RR8
ist abfragen möchten.
<
Ich habe versucht, diese Anweisung unter einer entsprechenden Spalte zu finden auf dem, was ich denke, es genannt werden soll, aber es ergab keine Ergebnisse.
SELECT * from dba_objects
WHERE object_name like '%DTN%'
Es gibt absolut keine Dokumentation zu dieser Datenbank und ich habe keine Ahnung, wo dieses Feld aus gezogen wird.
Alle Gedanken?
Lösung
Zitat:
Ich habe versucht, diese Aussage unter Verwendung von eine entsprechende Spalte zu finden, basierend auf was ich denke, es genannt werden soll, aber es ergab keine Ergebnisse. *
SELECT * from dba_objects WHERE object_name like '%DTN%'
Eine Spalte ist kein Objekt. Wenn Sie meinen, dass Sie der Spaltenname zu sein wie ‚% DTN%‘ erwarten, die Abfrage, die Sie wollen, ist:
SELECT owner, table_name, column_name FROM all_tab_columns WHERE column_name LIKE '%DTN%';
Aber wenn die Zeichenfolge ‚DTN‘ ist nur eine Vermutung auf Ihrer Seite, die wahrscheinlich nicht helfen.
Durch die Art und Weise, wie sicher sind Sie, dass ‚1/22 / 2008P09RR8‘ ist ein Wert direkt aus einer einzigen Spalte ausgewählt? Wenn Sie wissen gar nicht, wo es herkommt, es könnte eine Verkettung von mehreren Spalten sein, oder das Ergebnis einer Funktion, oder ein Wert in einem verschachtelten Tabellenobjekt sitzt. Sie könnten also auf eine Reihe von Ungereimtheiten, die versuchen, für diesen Wert jeder Spalte zu überprüfen. Können Sie sich nicht mit dem, was Client-Anwendung starten wird diesen Wert anzeigt und versuchen Sie herauszufinden, was abfragen um es zu erhalten, wird mit?
Wie auch immer, diciu Antwort gibt eine Methode von SQL-Abfragen erzeugen, jede Spalte jeder Tabelle für den Wert zu überprüfen. Sie können auch ähnliche Sachen vollständig in einer SQL-Sitzung mit einem PL / SQL-Block und dynamische SQL tun. Hier einige hastig geschriebenen Code dafür:
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;
/
Es gibt einige Möglichkeiten, wie Sie es auch effizienter machen könnten.
In diesem Fall angesichts der Wert, den Sie suchen, können Sie eindeutig jede Spalte beseitigen, die von NUMBER oder DATE-Typ ist, der die Anzahl der Abfragen reduzieren würde. Vielleicht sogar beschränkt es auf Spalten, in denen Art wie ‚% CHAR%‘ ist.
Statt eine Abfrage pro Spalte, können Sie eine Abfrage pro Tabelle wie folgt erstellen:
SELECT * FROM table1
WHERE column1 = 'value'
OR column2 = 'value'
OR column3 = 'value'
...
;
Andere Tipps
habe ich einige Änderungen an den obigen Code, um es schneller zu arbeiten, wenn Sie in nur einen Eigentümer gesucht werden. Sie müssen nur die v_owner 3 Variablen ändern, v_data_type und v_search_string zu passen, was Sie suchen.
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;
/
Ja, Sie können und Ihre DBA werden Sie hassen und finden Sie Ihre Schuhe auf den Boden nageln, weil das viele I / O verursachen und die Datenbank-Performance bringen wirklich nach unten, wie die Cache-Säuberungen.
select column_name from all_tab_columns c, user_all_tables u where c.table_name = u.table_name;
für einen Start.
würde ich mit den laufenden Abfragen starten, die v$session
und die v$sqlarea
verwenden. Dies ändert sich auf Basis der Oracle-Version. Dadurch wird der Raum einengen und nicht alles getroffen.
Ich weiß, das ist ein altes Thema. Aber ich sehe ein Kommentar auf die Frage zu fragen, ob es in getan werden könnte, SQL
anstatt mit PL/SQL
. Also dachte an eine Lösung zu stellen.
Die unten Demonstration ist auf Suche nach einem Wert in allen Spalten aller Tabellen in einem ganzen SCHEMA :
- Suchen Sie ein CHARACTER Typ
Sehen sie sich für den Wert 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>
- Suchen Sie einen NUMERIC Typen
Sehen sie sich für den Wert 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>
Hier ist eine weitere modifizierte Version, die einen niedrigeren Teilkette Spiel vergleichen wird. Dies funktioniert in 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;
/
Ich würde so etwas tun (erzeugt alle wählen Sie benötigen). Sie können sie auf sqlplus später füttern:
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;
Es ergibt sich:
select * from TBL1 where DESCRIPTION='val'
select * from TBL1 where ='val'
select * from TBL2 where Name='val'
select * from TBL2 where LNG_ID='val'
Und was es tut, ist -. Für jede table_name
von user_tables
jedes Feld erhalten (von ab) und erstellen Sie eine select * from table where Feld gleich 'val'
I modifizierte Skript Floods einmal eher für jede Tabelle auszuführen als für jede Spalte jeder Tabelle für eine schnellere Ausführung. Es erfordert Oracle 11g oder höher.
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;
/
Wenn wir kennen die Tabellen- und Spaltennamen, wollen aber die Anzahl der Zeichenfolge, um herauszufinden, wird für jedes Schema mit:
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;
Vorgehen gesamte Datenbank suchen:
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;
Ausführen 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;
Probenergebnisse
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.
Sie den Code ändern suchen case-insensitiv einer LIKE Abfrage stattdessen genau zu finden, Spiele ...
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;
ich nicht von einer einfachen Lösung auf dem SQL promprt. Howeve gibt es durchaus ein paar Tools wie Kröte und PL / SQL Developer, die eine GUI haben, wo ein Benutzer Eingabe der Zeichenfolge gesucht werden, und es wird wieder die Tabelle / Prozedur / Objekt, in dem diese zu finden ist.
Es gibt einige kostenlose Tools, die diese Art der Suche zu machen, zum Beispiel, dieser funktioniert gut und Quellcode verfügbar ist: https://sites.google.com/site/freejansoft/dbsearch
Sie werden den Oracle ODBC-Treiber benötigen und ein DSN dieses Tool zu benutzen.
Ich habe folgende Themen für @Lalit Kumars Antwort,
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
Die Lösung ist:
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"
/
- es abgeschlossen laufen - kein Fehler
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;
/
Leihen, etwas zu verbessern und zu vereinfachen von diese Blog-Post folgende einfache SQL-Anweisung scheint recht gut die Arbeit zu tun:
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";