Oracle

具有非標量類型的嵌套表上的多重集運算符

  • December 25, 2016

我有一個函式,它對兩個嵌套表執行多重操作並返回結果:

function odejmijEgz(tab typ_NT) return typ_NT is
 tab1 typ_NT := typ_NT();
 cursor c_osr_egz is select distinct o.id_osrodek oid, o.nazwa_o nazwa_o from egzaminy e
   right join osrodki o on e.id_osrodek = o.id_osrodek
   where e.id_osrodek is null;
 i number;
 begin
   for v_osr in c_osr_egz loop
     i := c_osr_egz%rowcount;
     tab1.extend;
     tab1(i) := v_osr;
   end loop;
 return tab multiset except tab1;
 end odejmijEgz; 

其中類型在 pl/sql 塊中聲明:

type typ_Rec is record(Id osrodki.id_osrodek%type,
                       Nazwa osrodki.nazwa_o%type);                 
type typ_NT is table of typ_Rec; 

該函式的參數是嵌套表,填充有記錄。

當我multiset except在函式中使用時出現錯誤:

Error: PLS-00306: wrong number or types of arguments in call to 'MULTISET_EXCEPT_ALL'

但是,如果我將其更改為multiset union有效。這些表屬於同一類型。那有什麼問題?

多組除外

嵌套表的元素類型必須是可比較的。

比較條件

如果兩個非標量類型的對象具有相同的命名類型並且它們的元素之間存在一一對應關係,則它們是可比較的。此外,使用者定義對像類型的嵌套表,即使它們的元素是可比較的,也必須在其上定義 MAP 方法,以便在相等或 IN 條件下使用。

問題是,以上不能用record類型來完成。record類型只有欄位,不能有成員函式。此外:

記錄比較

無法在本地測試記錄的無效性、平等性或不平等性。

這些 BOOLEAN 表達式是非法的:

  • My_Record 為空
  • 我的記錄_1 = 我的記錄_2
  • 我的_記錄_1 > 我的_記錄_2

這失敗了:

create or replace package p1 as
 type typ_Rec is record(id customers.customer_id%type, name customers.cust_first_name%type);                 
 type typ_NT is table of typ_Rec;
 function f1 (tab typ_NT) return typ_NT;
end;
/

Package created.

create or replace package body p1 as
 function f1 (tab typ_NT) return typ_NT as
   tab1 typ_NT := typ_NT();
 begin
   return tab multiset except tab1;
 end;
end;
/

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY P1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: Statement ignored
5/12     PLS-00306: wrong number or types of arguments in call to
        'MULTISET_EXCEPT_ALL'

UNION有效,因為您沒有指定ALLor DISTINCT,在這種情況下,UNION ALL是預設值。UNION ALL不需要進行比較。但是,如果您嘗試UNION DISTINCT(刪除重複項),那也將失敗:

create or replace package body p1 as
 function f1 (tab typ_NT) return typ_NT as
   tab1 typ_NT := typ_NT();
 begin
   return tab multiset union distinct tab1;
 end;
end;
/

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY P1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: Statement ignored
5/12     PLS-00306: wrong number or types of arguments in call to
        'MULTISET_UNION_DISTINCT'

你需要一個object類型。

create or replace type typ_Obj as object
(
 id number(6),
 name varchar2(20)
);
/

Type created.

create or replace package p1 as
 type typ_NT is table of typ_Obj;
 function f1 (tab typ_NT) return typ_NT;
end;
/

Package created.

create or replace package body p1 as
 function f1 (tab typ_NT) return typ_NT as
   tab1 typ_NT := typ_NT();
 begin
   return tab multiset except tab1;
 end;
end;
/

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY P1:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: Statement ignored
5/12     PLS-00306: wrong number or types of arguments in call to
        'MULTISET_EXCEPT_ALL'

注意它仍然失敗,因為我沒有定義MAP函式,我沒有告訴數據庫它如何比較兩個使用者定義的對象。現在再試一次,這次定義MAP(這裡我假設對像有唯一的標識符,如果它們的標識符相等,則兩個對象相等):

create or replace type typ_Obj as object
(
 id number(6),
 name varchar2(20),
 MAP MEMBER FUNCTION get_idno RETURN NUMBER
);
/

Type created.

CREATE or replace TYPE BODY typ_Obj AS
 MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
 BEGIN
   RETURN id;
 END;
END;
/

Type body created.

create or replace package body p1 as
 function f1 (tab typ_NT) return typ_NT as
   tab1 typ_NT := typ_NT();
 begin
   return tab multiset except tab1;
 end;
end;
/

Package body created.

最後它起作用了,沒有警告。

引用自:https://dba.stackexchange.com/questions/159045