How to compare complex collections in Oracle?

Let us say I have two table types (tables of object types) that I want to compare for equality...

The object types have multiple fields, say, an integer, varchar2, and date.

I have seen examples where people use MULTISET EXCEPT in order to effectively do a MINUS on two tables of INTEGER.

But this does not work with two tables of complex object types.

Also I have seen mentioned the use of MAP MEMBER FUNCTION in order to make complex collections work when using the SET operator, but no mention of MULTISET functionality.

The current way I am comparing for equality is to take table type 1 (TT1) and table type 2 (TT2) and say they are equal if TT1 MINUS TT2 = 0 AND TT2 MINUS TT1 = 0. But here I am just selecting the PK from both tables for the MINUS, I would also like to be able to compare more than one field.

I am hoping MULTISET is faster?

Thanks.

Answers


Yes, you can use a MAP MEMBER FUNCTION to support comparing nested tables of types.

--#1: Create object
create or replace type type1 is object
(
    a integer,
    b varchar2(100),
    c date,
    map member function compare return raw
);
/

--#2: Create map function for comparisons.
--Returns the concatenated RAW of all attributes.
--Note that this will consider NULLs to be equal!
create or replace type body type1 as
    map member function compare return raw is
    begin
        return
            utl_raw.cast_to_raw(to_char(a))||
            utl_raw.cast_to_raw(b)||
            utl_raw.cast_to_raw(to_char(c, 'DD-MON-YYYY HH24:MI:SS'));

    end;
end;
/

--#3: Create nested table of the types
create or replace type type1_nt is table of type1;
/

--#4: Compare.
--You could use MULTISET, but it's easier to use regular operators like "<>" "and =".
declare
    tt1 type1_nt := type1_nt(type1(0, 'A', date '2000-01-01'),
                             type1(0, 'A', date '2000-01-01'));
    tt2 type1_nt := type1_nt(type1(0, 'B', date '2000-01-01'),
                             type1(0, 'B', date '2000-01-01'));
    tt3 type1_nt := type1_nt(type1(0, 'B', date '2000-01-01'),
                             type1(0, 'B', date '2000-01-01'));
begin
    if tt1 <> tt2 and tt2 = tt3 then
        dbms_output.put_line('Pass');
    else
        dbms_output.put_line('Fail');
    end if;
end;
/

I don't know if this would be faster than manually comparing each attribute. But I would guess the difference won't be significant.


Need Your Help

NPM has stopped working on Windows 7 64bit, hangs on install/update

windows node.js npm

At some point my version of NPM stopped working. It seems to have happened when I tried to update npm (from 1.4 shipping with node to a modern 2.x version) a few weeks ago and has steadily gotten ...

mysql is slow with InnoDB during insert compared to MYISAM

mysql performance logging insert innodb

I just installed MySQL 5.5 which have InnoDB default engine and realized INSERT queries really slow! After disabling general-log it got a bit better but still real slow. I analyzing mysql to find the