Comments on: Compare tables with the minus operator, even if they contain clobs and/or blobs. Friends of Oracle and Java Fri, 27 Feb 2015 08:30:27 +0000 hourly 1 By: Harry Dragstra Fri, 06 Jul 2012 09:26:16 +0000 Well, you better forget about my last comment… the ORA_HASH function, used in the way I do, isn’t consistent in the result value.
And if result values differ in time for identical input, comparing two tables that use this function will (almost ) always result in 1 ( tables differ ).
See for more info about the ORA_HASH function:

By: Harry Dragstra Fri, 06 Jul 2012 07:49:47 +0000 I discovered that there is an easy ( without using ) full proof solution, by applying
the ORA_HASH function ( available as of 10g Release 1 ).

The docs – – mention explicitly that there is “no restrictions on the type or length of data”, so I tested it on LONG’s too.
And indeed… no problem at all.

Here is the the changed code, using the ORA_HASH function now:

SQL> set linesize 300 pagesize 0 heading off
SQL> select text from user_source where type=’FUNCTION’ and name =’DIFF_TABLES’ order by line;
FUNCTION Diff_Tables
( P_name_tab1 VARCHAR2
, P_name_tab2 VARCHAR2
, P_owner_tab1 VARCHAR2 := USER
, P_owner_tab2 VARCHAR2 := USER )

v_tab1 VARCHAR2(100) := UPPER(TRIM(P_owner_tab1||’.’||P_name_tab1));
v_tab2 VARCHAR2(100) := UPPER(TRIM(P_owner_tab2||’.’||P_name_tab2));
v_clist VARCHAR2(4000) := NULL;
v_col VARCHAR2(100);
cntr PLS_INTEGER := 0;
cnt1 NUMBER := 0;
cnt2 NUMBER := 0;
v_ret PLS_INTEGER := 0;


— setup the column list
for x in ( select column_name
, data_type
from dba_tab_columns
where owner||’.’||table_name = v_tab1
order by column_id )
cntr := cntr + 1;
if x.data_type in (‘CLOB’,’BLOB’,’LONG’) then
v_col := ‘ORA_HASH(‘||x.column_name||’)';
— v_col := ‘DBMS_LOB.SUBSTR(‘||x.column_name||’,2000), DBMS_LOB.GETLENGTH(‘||x.column_name||’)';
v_col := x.column_name;
end if;
if cntr != 1 then
v_col := ‘,’||v_col;
end if;
v_clist := v_clist||v_col;
end loop;

— compare
EXECUTE IMMEDIATE ‘select count(*) from ( select ‘||v_clist||’ from ‘||v_tab1||’ minus select ‘||v_clist||’ from ‘||v_tab2||’ )’ INTO cnt1;
EXECUTE IMMEDIATE ‘select count(*) from ( select ‘||v_clist||’ from ‘||v_tab2||’ minus select ‘||v_clist||’ from ‘||v_tab1||’ )’ INTO cnt2;

— return 0 if tables match, and 1 if tables differ.
if (cnt1+cnt2) > 0 then
v_ret := 1;
end if;

return v_ret;

END Diff_Tables;

50 rows selected.