Sei sulla pagina 1di 5

HOW CAN YOU ANSWER?

Author JP Vijaykumar Date Sept 14th 2012 This question: "What are the table_names & column_names that contained a specific string value? " I can search table_names/column_names in Oracle's data dictionary tables/views. How to search tables' columns for a specific string value. To answer the question, I wrote a pl/sql procedure. ASSUMPTIONS: 01 The Oracle database is identified, where the procedure will be executed. 02 The specific value to be verified in question is a string. 03 This string value is from either CHAR or VARCHAR2 data type column. 04 Search columns with data_length >= length of the STRING value. CONSTRAINTS: 01 The pl/sql procedure has to scan all VARCHAR2 & CHAR data type columns. 02 All the VARCHAR2 & CHAR data type columns in tables may not be indexed. 03 Depending on the number of tables with VARCHAR2 & CHAR data_type columns and number of rows, this procedure may take few hours to few days to complete. 04 If the string value is very long, our search may complete in less time. If the string value is short, our search may take longer time. 05 In the event, the string value is lower case or mixed case, better convert the column value & string value to upper case and compare. The following pl/sql procedure was executed in our db. --FIRST RUN --INITIAL PROCEDURE --PER COLUMN ONE SELECT ON THE TABLE IS EXECUTED set serverout on size 1000000 timing on declare v_stg varchar2(50):='SAI VEEKSHA'; --INPUT SEARCH STRING --v_stg varchar2(50):='RAMAMOHAN RAO'; --INPUT SEARCH STRING v_num number:=0; v_len number:=0; begin execute immediate 'alter session set cursor_sharing=similar'; v_len:=length(v_stg); dbms_output.put_line(v_len); for c1 in (select table_name,column_name from user_tab_columns where data_type in ('CHAR','VARCHAR2') and data_length >= v_len order by 1 ) loop begin execute immediate 'select count(1) from '||c1.table_name||' where '||c1.column_n ame|| ' like '''||'%'||v_stg||'%'||''' ' into v_num; dbms_output.put_line('select count(1) from '||c1.table_name||' where '||c1.colum n_name|| ' like '''||'%'||v_stg||'%'||''' into v_num'); if (v_num > 0) then dbms_output.put_line(c1.table_name||' '||c1.column_name||' '||v_stg||' '||v_n um); end if; exception

when others then dbms_output.put_line(sqlerrm); end; end loop; end; / 11 ............ ............. ........... Elapsed: 27:48:59.82 --The script took almost 28 hrs to get me the required info. --I want to cut down the run time. --SECOND RUN -- MODIFIED THE PROCEDURE --ONE SELECT EXECUTED PER TABLE, CONCATINATING ALL CANDIDATE COLUMNS set serverout on size 1000000 timing on declare v_stg varchar2(50):='SAI VEEKSHA'; --INPUT SEARCH STRING --v_stg varchar2(50):='RAMAMOHAN RAO'; --INPUT SEARCH STRING v_num number:=0; v_cmd varchar2(4000); v_len number:=0; begin --execute immediate 'alter session set cursor_sharing=similar'; execute immediate 'alter session set cursor_sharing=force'; v_len:=length(v_stg); dbms_output.put_line(v_len); for c1 in (select distinct table_name from user_tab_columns where data_type in ('CHAR','VARCHAR2') order by 1) loop begin v_cmd:='where'; for c2 in (select column_name from user_tab_columns where table_name = c1.table_name and data_type in ('CHAR','VARCHAR2') and data_length >= v_len order by 1 ) loop begin if ( v_cmd = 'where' ) then v_cmd:=v_cmd||' '||c2.column_name||' like '''||'%'||v_stg||'%'||''' '; else v_cmd:=v_cmd||' or '||c2.column_name||' like '''||'%'||v_stg||'%'||''' '; end if; exception when others then dbms_output.put_line(sqlerrm); end; end loop; v_cmd:='select count(1) from '||c1.table_name||' '||v_cmd; execute immediate v_cmd into v_num; if (v_num > 0) then dbms_output.put_line(v_cmd||' '||v_num); end if; exception when others then dbms_output.put_line(v_cmd||' '||sqlerrm);

end; end loop; end; / ........... ......... ......... Elapsed: 13:44:02.87 --THE SECOND RUN CAME DOWN TO ABOUT 14 HRS. --I WILL MODIFY THE PROCEDURE FURTHER AND SEE HOW MUCH I GAIN. --THIRD RUN -- MODIFIED THE QUERY --ONLY QUERY TABLES WITH CHAR & VARCHAR DATATYPE COLUMNS -- AND LENGTH > STRING LENGTH -- ALSO I AM FILTERING VIEWS FROM MY SEARCHING CONDITION. select count(table_name) from user_tab_columns; COUNT(TABLE_NAME) ----------------32993 select count(table_name) from user_tab_columns where table_name NOT IN (select view_name from user_views); COUNT(TABLE_NAME) ----------------30284 Since views are based on tables, views' details exist in the user_tab_columns view. To avoid redundency, filtered all views from my procedure. set serverout on size 1000000 timing on declare v_stg varchar2(50):='SAI VEEKSHA'; --INPUT SEARCH STRING --v_stg varchar2(50):='RAMAMOHAN RAO'; --INPUT SEARCH STRING v_num number:=0; v_cmd varchar2(4000); v_len number:=0; begin --execute immediate 'alter session set cursor_sharing=similar'; execute immediate 'alter session set cursor_sharing=force'; v_len:=length(v_stg); dbms_output.put_line(v_len); for c1 in (select distinct table_name from user_tab_columns where data_type in ('CHAR','VARCHAR2') and data_length >= v_len and table_name NOT IN (select view_name from user_views) order by 1 ) loop begin v_cmd:='where'; for c2 in (select column_name from user_tab_columns where table_name = c1.table_name and data_type in ('CHAR','VARCHAR2') and data_length >= v_len order by 1 ) loop

begin if ( v_cmd = 'where' ) then v_cmd:=v_cmd||' '||c2.column_name||' like '''||'%'||v_stg||'%'||''' '; else v_cmd:=v_cmd||' or '||c2.column_name||' like '''||'%'||v_stg||'%'||''' '; end if; exception when others then dbms_output.put_line(sqlerrm); end; end loop; v_cmd:='select count(1) from '||c1.table_name||' '||v_cmd; execute immediate v_cmd into v_num; if (v_num > 0) then dbms_output.put_line(v_cmd||' '||v_num); end if; exception when others then dbms_output.put_line(v_cmd||' '||sqlerrm); end; end loop; end; / .............. ............... ........... Elapsed: 02:10:26.13 *******************************************11/06/2012*************************** **** I had the opportunity to tesh the script's usability in another occasion. This time, the string might have been stored in CLOBS/BLOBS also. I had modified the script accordingly. set serverout on size 1000000 timing on linesize 140 declare v_stg varchar2(4):='RAMA'; --INPUT SEARCH STRING --v_stg varchar2(50):='RAMAMOHAN RAO'; --INPUT SEARCH STRING v_num number:=0; v_cmd varchar2(4000); v_col varchar2(100); v_len number:=0; begin --execute immediate 'alter session set cursor_sharing=similar'; --execute immediate 'alter session set cursor_sharing=force'; v_len:=100; --length(v_stg); dbms_output.put_line(v_len); for c1 in (select distinct table_name from user_tab_columns where data_type in ('CHAR','VARCHAR2','BLOB','CLOB') and data_length >= v_len and table_name NOT IN (select view_name from user_views) order by 1 ) loop begin v_cmd:='where'; for c2 in (select column_name,data_type from user_tab_columns where table_name = c1.table_name and data_type in ('CHAR','VARCHAR2','BLOB','CLOB')

and data_length >= v_len order by 1 ) loop begin if ( c2.data_type = 'BLOB' OR c2.data_type = 'CLOB') then v_col:='dbms_lob.substr('||c2.column_name||',200)'; else v_col:=c2.column_name; end if; if ( v_cmd = 'where' ) then v_cmd:=v_cmd||' '||v_col||' like '''||'%'||v_stg||'%'||''' '; else v_cmd:=v_cmd||' or '||v_col||' like '''||'%'||v_stg||'%'||''' '; end if; exception when others then dbms_output.put_line(sqlerrm); end; end loop; v_cmd:='select /*+ parallel('||c1.table_name||' 4)*/ count(1) from '||c1.table_n ame||' '||v_cmd; execute immediate v_cmd into v_num; if (v_num > 0) then dbms_output.put_line(v_cmd||' '||v_num); end if; exception when others then dbms_output.put_line(v_cmd||' '||sqlerrm); end; end loop; end; / References: http://www.morganslibrary.com/hci/hci015.html http://www.databasejournal.com/features/oracle/article.php/3700201/Tuning-an-Ora cle-Procedure.htm

Potrebbero piacerti anche