Oracle PL SQL:比较两个存储过程返回的引用游标结果

时间:2014-01-29 21:09:50

标签: sql oracle plsql cursor

我获得了一个存储过程,它生成一个打开的游标,作为输出传递给报告工具。我重写了这个存储过程以提高性能。我想要做的是显示给定的一组输入参数的两个结果集是相同的。

相当于:

的东西
select * from CURSOR_NEW
minus
select * from CURSOR_OLD
     union all
select * from CURSOR_OLD
minus
select * from CURSOR_NEW

每个游标从一大部分表中返回几十列。每行都有一个id值,以及该id的其他列值的长列表。我想查一下:

  1. 两个游标都返回同一组ID(我已经检查了这个)
  2. 两个游标对于他们共有的每个id具有相同的值列表
  3. 如果它只是一列或两列,我可以连接它们并找到一个哈希值,然后在光标上加总。或者另一种方法可能是创建一个父程序,将光标结果插入到全局临时表中并比较结果。但是,由于它是几十个专栏,我试图找到一种不那么强力的方法来进行比较。

    如果解决方案可以针对涉及不同游标的其他情况进行扩展,那么这将是很好的,因此不必每次都手动重写,因为这是我经常遇到的情况。

2 个答案:

答案 0 :(得分:1)

我找到了一种方法来做到这一点。这比我想象的要复杂得多。我最终使用了一些DBMS_SQL过程,允许将REFCURSOR转换为定义的游标。 Oracle在此处提供了相关文档: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm#LNPLS00001

之后,我将行值连接成一个字符串并打印出哈希值。对于更大的游标,我将更改concat_col_vals以使用CLOB来防止它溢出。

p_testCursors返回一个简单的refcursor,用于示例目的。

declare
  cx_1              sys_refcursor;
  c                 NUMBER;
  desctab           DBMS_SQL.DESC_TAB;
  colcnt            NUMBER;
  stringvar         VARCHAR2(4000);
  numvar            NUMBER;
  datevar           DATE;
  concat_col_vals   varchar2(4000);
  col_hash          number;
  h                 raw(32767);
  n                 number;

BEGIN
  p_testCursors(cx_1);

  c := DBMS_SQL.TO_CURSOR_NUMBER(cx_1);
  DBMS_SQL.DESCRIBE_COLUMNS(c, colcnt, desctab);

  -- Define columns:
  FOR i IN 1 .. colcnt LOOP
    IF desctab(i).col_type = 2 THEN
      DBMS_SQL.DEFINE_COLUMN(c, i, numvar);
    ELSIF desctab(i).col_type = 12 THEN
      DBMS_SQL.DEFINE_COLUMN(c, i, datevar);
      -- statements
    ELSE
      DBMS_SQL.DEFINE_COLUMN(c, i, stringvar, 4000);
    END IF;
  END LOOP;

  -- Fetch rows with DBMS_SQL package:
  WHILE DBMS_SQL.FETCH_ROWS(c) > 0 LOOP
  concat_col_vals := '~';
    FOR i IN 1 .. colcnt LOOP
      IF (desctab(i).col_type = 1) THEN
        DBMS_SQL.COLUMN_VALUE(c, i, stringvar);
        --Dbms_Output.Put_Line(stringvar);
        concat_col_vals := concat_col_vals || '~' || stringvar;
      ELSIF (desctab(i).col_type = 2) THEN
        DBMS_SQL.COLUMN_VALUE(c, i, numvar);
        --Dbms_Output.Put_Line(numvar);
        concat_col_vals := concat_col_vals || '~' || to_char(numvar);
      ELSIF (desctab(i).col_type = 12) THEN
        DBMS_SQL.COLUMN_VALUE(c, i, datevar);
        --Dbms_Output.Put_Line(datevar);
        concat_col_vals := concat_col_vals || '~' || to_char(datevar);
        -- statements
      END IF;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE(concat_col_vals);
    col_hash :=  DBMS_UTILITY.GET_SQL_HASH(concat_col_vals, h, n);
    DBMS_OUTPUT.PUT_LINE('Return Value: ' || TO_CHAR(col_hash));
    DBMS_OUTPUT.PUT_LINE('Hash: ' || h);
  END LOOP;

  DBMS_SQL.CLOSE_CURSOR(c);

END;
/

答案 1 :(得分:0)

这对Oracle来说不是一件容易的事。

你可以在dba-oracle web上找到

非常好的文章
Sql patterns symmetric diff
Convert set to join sql parameter

如果您经常需要,您可以:

  • 添加“哈希列”并使用“使用触发器插入”或
  • 来填充它
  • 为游标输出中的每个表获取唯一值(创建唯一索引)并仅比较此列与anijoin

你可以在文章中找到其他可能性。