Schema wide text search
From WickyWiki
Search full schema for text.
The pl/sql block is a simple (but slow) way to find a certain text or number in your Oracle database schema. The result will be in the table 'tmp_searchresult'. Any exceptions will be reported in the 'found_error' column. For example when datatypes are not supported.
-- create
drop table tmp_searchresult;
create table tmp_searchresult(
speed timestamp default systimestamp
, table_name varchar2(32)
, found_count NUMBER
, table_count number
, first_rowid rowid
, found_error clob)
;
-- search
BEGIN
DECLARE
search_txt VARCHAR2(50) := 'Stichting Waternet';
search_num NUMBER;
search_dat date;
TYPE curTyp IS REF CURSOR;
cursor1 curTyp;
cursor2 curTyp;
where_txt CLOB;
v_sql VARCHAR2(10000);
v_table_name VARCHAR2(40);
v_column_name VARCHAR2(40);
v_column_where VARCHAR2(100);
v_column_type VARCHAR2(40);
v_found number;
v_message clob;
v_rowid rowid;
v_id NUMBER;
v_tables_count number := 0;
BEGIN
delete tmp_searchresult;
OPEN cursor2 FOR 'select table_name
from user_tables
where not table_name like ''TMP%''
and not table_name like ''%$%''
order by table_name';
LOOP
FETCH cursor2 INTO v_table_name;
EXIT WHEN cursor2%NOTFOUND;
v_tables_count := v_tables_count + 1;
where_txt := NULL;
BEGIN
search_num:=TO_NUMBER(search_txt);
EXCEPTION WHEN OTHERS THEN
search_num:=NULL;
END;
BEGIN
search_dat:=TO_DATE(search_txt,'DD-MM-YYYY');
EXCEPTION WHEN OTHERS THEN
search_dat:=NULL;
END;
OPEN cursor1 FOR 'select column_name, data_type from cols
where not DATA_TYPE in (''BLOB'',''SDO_GEOMETRY'',''LONG'')
and table_name='''||v_table_name||''' order by COLUMN_ID';
LOOP
FETCH cursor1 INTO v_column_name, v_column_type;
EXIT WHEN cursor1%NOTFOUND;
IF NOT search_num is NULL THEN
if v_column_type='NUMBER' then
v_column_where:='"'||v_column_name||'"'||'='||search_txt;
else
v_column_where:=NULL;
end if;
ELSIF NOT search_dat is NULL THEN
if v_column_type='DATE' then
v_column_where:='upper(to_char('||'"'||v_column_name||'"'||',''DD-MM-YYYY''))=upper('''||search_txt||''')';
else
v_column_where:=NULL;
end if;
ELSIF NOT search_txt is NULL THEN
if v_column_type='NUMBER' or v_column_type='DATE' then
v_column_where:=NULL;
else
v_column_where:='upper("'||v_column_name||'")'||' like ''%' || upper(search_txt) || '%''';
end if;
END IF;
IF NOT v_column_where is NULL THEN
IF where_txt is NULL THEN
where_txt := v_column_where;
ELSE
where_txt := where_txt || ' OR ' || v_column_where;
END IF;
END IF;
END LOOP;
CLOSE cursor1;
IF NOT where_txt is NULL THEN
BEGIN
v_sql:='insert into tmp_searchresult(table_name, found_count, first_rowid)
select :v_table_name, count(*), max(rowid)
from "'||v_table_name||'"
where '||where_txt
;
execute immediate v_sql using v_table_name;
commit;
EXCEPTION WHEN OTHERS THEN
v_message := 'sql=' || v_sql || ', backtrace=' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE || ', sqlerrm=' || SQLERRM;
insert into tmp_searchresult(speed,table_name,found_error) values (sysdate,v_table_name, v_message);
commit;
END;
END IF;
END LOOP;
CLOSE cursor2;
insert into tmp_searchresult(table_name, found_count, table_count, first_rowid) values ('<searched>', null, v_tables_count, null);
END;
END;
/
-- result
select 'select * from "'||table_name||'" where rowid = '''||FIRST_ROWID||'''; --'||FOUND_COUNT
from tmp_searchresult
where FOUND_COUNT>0
order by table_name
;