比较两个Oracle类型的每列中的值

时间:2010-04-09 16:00:30

标签: oracle plsql

我今天一直在玩pluto-test-framework,我想将一些现有的功能纳入测试工具中。

我有很多这类规范的功能。

   FUNCTION DO_SOME_STUFF   (pOldSchedule       IN      SCHEDULE_OBJ,
                             pNewSchedule          OUT  SCHEDULE_OBJ,
                             pLoggerContext     IN OUT  LOGGER_CONTEXT_OBJ)
   RETURN NUMBER;

它需要pOldSchedule,对它做一些事情,然后返回pNewSchedule。 logger_context只是记录。

作为测试的一部分,我希望能够比较该类型的每个列中的值,而无需编写单独的IF语句。

它需要返回布尔值来表示pOldSchedule和pNewSchedule是否匹配。

有什么想法吗?

1 个答案:

答案 0 :(得分:6)

直接的相等测试适用于嵌套表:

SQL> declare
  2      type nt is table of number;
  3      nt1 nt;
  4      nt2 nt;
  5      nt3 nt;
  6  begin
  7      nt1 := nt(1,2,3);
  8      nt2 := nt(1,2,3);
  9      if nt1 = nt2 then
 10          dbms_output.put_line('NT2 is the same nested table as NT1');
 11      else
 12          dbms_output.put_line('NT2 is a different nested table from NT1');
 13      end if;
 14      nt2 := nt(1,2,3,4);
 15      if nt1 = nt3 then
 16          dbms_output.put_line('NT3 is the same nested table as NT1');
 17      else
 18          dbms_output.put_line('E3 is a different nested table from NT1');
 19      end if;
 20  end;
 21  /
NT2 is the same nested table as NT1
E3 is a different nested table from NT1

PL/SQL procedure successfully completed.

SQL>

然而,完全对象的情况并非如此:

SQL> create or replace type new_emp as object (
  2      ename varchar2(10)
  3      , sal number
  4      , deptno number
  5      , job varchar2(10))
  6  /

Type created.

SQL> declare
  2      e1 new_emp;
  3      e2 new_emp;
  4  begin
  5      e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
  6      e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
  7      if e1 = e2 then
  8          dbms_output.put_line('E2 is the same as E1');
  9      else
 10          dbms_output.put_line('E2 is different from E1');
 11      end if;
 12  end;
 13  /
    if e1 = e2 then
          *
ERROR at line 7:
ORA-06550: line 7, column 11:
PLS-00526: A MAP or ORDER function is required for comparing objects in PL/SQL.


SQL>

我们需要明确定义一个成员函数来执行比较。所以这是具有MAP功能的相同对象。示例实现生成一个散列字符串,如果我们想要存储该值以供以后比较,它很有用,但它可以只返回连接的字符串(特别是默认情况下不会授予DBMS_CRYPTO上的EXECUTE)。 NVL()函数是必要的,以避免(null,value)和(value,null)被评估为相等。使用魔法值时总是存在风险,因此我们需要仔细选择它们。

SQL> create or replace type new_emp as object (
  2      ename varchar2(10)
  3      , sal number
  4      , deptno number
  5      , job varchar2(10)
  6      , map member function equals return raw)
  7  /

Type created.

SQL> create or replace type body new_emp as
  2      map member function equals return raw
  3      is
  4      begin
  5          return dbms_crypto.hash(
  6                     utl_raw.cast_to_raw(nvl(self.ename,'***')||
  7                                          nvl(self.sal,-99)||
  8                                          nvl(self.deptno,-99)||
  9                                          nvl(self.job,'***')
 10                                        )
 11                                   , 1);
 12      end equals;
 13  end;
 14  /

Type body created.

SQL>

现在我们有了比较对象实例的基础:

SQL> declare
  2      e1 new_emp;
  3      e2 new_emp;
  4  begin
  5      e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
  6      e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
  7      if e1 = e2 then
  8          dbms_output.put_line('E2 is the same as E1');
  9      else
 10          dbms_output.put_line('E2 is different from E1');
 11      end if;
 12  end;
 13  /
E2 is the same as E1

PL/SQL procedure successfully completed.

SQL>    

您可能想知道为什么Oracle默认不这样做。好吧,TYPE实现只允许一个比较方法(如果我们有MAP函数,我们不能有ORDER函数),所以我们需要有能力选择我们自己的相等定义。例如,名为rectangle的类型可能具有名为area()的MAP函数,该函数返回self.width * self.length