Monday, May 28, 2012

Comparing Nested Table Collections

Oracle 11g

Oracle lets you compare PL/SQL nested table collections, but there are several rules to keep in mind. These rules are evaluated in the order given.

Create these types and this helper procedure to test these rules.

create type type1_nt is table of varchar2(100)
/
CREATE PROCEDURE p_comp_coll(p_col1 IN type1_nt,
                             p_col2 IN type1_nt) IS
BEGIN
  IF p_col1 = p_col2 THEN
    dbms_output.put_line('EQUAL');
  ELSIF p_col1 <> p_col2 THEN
    dbms_output.put_line('NOT EQUAL');
  ELSE
    dbms_output.put_line('NULL');
  END IF;
END;
/

Rule 1. Nested table collections of objects or records cannot be compared.

SQL> DECLARE
  2    TYPE varrec_t IS RECORD(
  3      val1 VARCHAR2(100));
  4    TYPE mycol_t IS TABLE OF varrec_t;
  5    l_coll1 mycol_t;
  6    l_coll2 mycol_t;
  7  BEGIN
  8    IF l_coll1 = l_coll2 THEN -- will not compile
  9      NULL;
 10    END IF;
 11  END;
 12  /
 
DECLARE
  TYPE varrec_t IS RECORD(
    val1 VARCHAR2(100));
  TYPE mycol_t IS TABLE OF varrec_t;
  l_coll1 mycol_t;
  l_coll2 mycol_t;
BEGIN
  IF l_coll1 = l_coll2 THEN -- will not compile
    NULL;
  END IF;
END;
 
ORA-06550: line 9, column 14:
PLS-00306: wrong number or types of arguments in call to '='
ORA-06550: line 9, column 3:
PL/SQL: Statement ignored

Rule 2: Collections must be of EXACTLY the same type. Being based on the same element type is not sufficient.


This will not compile:
SQL> create type type2_nt is table of varchar2(100) -- same as type1_nt
  2  /
  
 
Type created

SQL> declare
  2  l_col1 type1_nt := type1_nt('data');
  3  l_col2 type2_nt := type2_nt('data');
  4  begin
  5  if l_col1 = l_col2 then -- not allowed
  6  null;
  7  end if;
  8  end;
  9  /
 
declare
l_col1 type1_nt := type1_nt('data');
l_col2 type2_nt := type2_nt('data');
begin
if l_col1 = l_col2 then
null;
end if;
end;
 
ORA-06550: line 6, column 11:
PLS-00306: wrong number or types of arguments in call to '='
ORA-06550: line 6, column 1:
PL/SQL: Statement ignored

Rule 3: If either of the nested tables is unitialized, the result is NULL.

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data');
  3    l_col2 type1_nt;
  4  BEGIN
  5    p_comp_coll(l_col1, l_col2);
  6  END;
  7  /
 
NULL
 
PL/SQL procedure successfully completed

SQL> DECLARE
  2    l_col1 type1_nt;
  3    l_col2 type1_nt;
  4  BEGIN
  5    p_comp_coll(l_col1, l_col2);
  6  END;
  7  /
 
NULL
 
PL/SQL procedure successfully completed

Rule 4: If the collections have different numbers of elements, they are not equal.

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data', NULL);
  3    l_col2 type1_nt := type1_nt('data');
  4  BEGIN
  5    p_comp_coll(l_col1, l_col2);
  6  END;
  7  /
 
NOT EQUAL
 
PL/SQL procedure successfully completed

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data');
  3    l_col2 type1_nt := type1_nt('data');
  4  BEGIN
  5    l_col2.extend();
  6    p_comp_coll(l_col1, l_col2);
  7  END;
  8  /
 
NOT EQUAL
 
PL/SQL procedure successfully completed

Rule 5: If the collections have the same number of elements but any of those elements are NULL, the collections are not equal. Note that '' is NOT treated as NULL when comparing collections!

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data',
  3                                NULL);
  4    l_col2 type1_nt := type1_nt('data',
  5                                NULL);
  6  BEGIN
  7    p_comp_coll(l_col1,
  8                l_col2);
  9  END;
 10  /
 
NULL
 
PL/SQL procedure successfully completed

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data1',
  3                                'data2');
  4    l_col2 type1_nt := type1_nt('',
  5                                'data1');
  6  BEGIN
  7    p_comp_coll(l_col1,
  8                l_col2);
  9  
 10    dbms_output.put_line('Coll1 size:' || l_col1.count);
 11    dbms_output.put_line('Coll2 size:' || l_col2.count);
 12    IF '' IS NULL THEN
 13      dbms_output.put_line('yes, '''' is generally considered to be null!');
 14    END IF;
 15  END;
 16  /
 
NOT EQUAL
Coll1 size:2
Coll2 size:2
yes, '' is generally considered to be null!
 
PL/SQL procedure successfully completed

Rule 6: If the collections have the same number of elements, none of the elements are NULL, and all of the values are the same regardless of order, the collections are equal.

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data1',
  3                                'data2');
  4    l_col2 type1_nt := type1_nt('data1',
  5                                'data2');
  6  BEGIN
  7    p_comp_coll(l_col1,
  8                l_col2);
  9  END;
 10  /
 
EQUAL
 
PL/SQL procedure successfully completed

SQL> DECLARE
  2    l_col1 type1_nt := type1_nt('data1',
  3                                'data2');
  4    l_col2 type1_nt := type1_nt('data2',
  5                                'data1');
  6  BEGIN
  7    p_comp_coll(l_col1,
  8                l_col2);
  9  END;
 10  /
 
EQUAL
 
PL/SQL procedure successfully completed