Oracle PL SQL:比较两个存储过程返回的引用游标结果
Posted
技术标签:
【中文标题】Oracle PL SQL:比较两个存储过程返回的引用游标结果【英文标题】:Oracle PL SQL: Comparing ref cursor results returned by two stored procs 【发布时间】:2014-01-29 21:09:49 【问题描述】:我得到了一个存储过程,它生成一个打开的游标,该游标作为输出传递给报告工具。我重写了这个存储过程来提高性能。我想做的是表明对于给定的一组输入参数,这两个结果集是相同的。
相当于:
select * from CURSOR_NEW
minus
select * from CURSOR_OLD
union all
select * from CURSOR_OLD
minus
select * from CURSOR_NEW
每个游标从大量表子集中返回几十列。每行都有一个 id 值,以及该 id 的其他列值的长列表。我想检查一下:
-
两个游标都返回相同的 id 集(我已经检查过了)
两个游标的每个 id 都有相同的值列表
如果它只是一两列,我可以将它们连接起来并找到一个哈希值,然后在光标上对其求和。或者另一种方法可能是创建一个父程序,将游标结果插入全局临时表并比较结果。但由于它有几十个专栏,我试图找到一种不那么暴力的方法来进行比较。
此外,如果该解决方案可针对涉及不同游标的其他情况进行扩展,那就太好了,这样就不必每次都手动重写,因为这是我经常遇到的情况。
【问题讨论】:
【参考方案1】:我想出了一个办法。这比我预期的要复杂得多。我最终使用了一些允许将 REFCURSOR 转换为已定义游标的 DBMS_SQL 过程。 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;
/
【讨论】:
【参考方案2】:这对 Oracle 来说并非易事。
非常好的文章您可以在 dba-oracle 网站上找到:Sql patterns symmetric diff 和Convert set to join sql parameter
如果您经常需要,您可以:
添加“哈希列”并始终使用触发器插入填充它,或者 为游标输出中的每个表获取唯一值(创建唯一索引)并仅将此列与 anijoin 进行比较您可以在文章中找到其他可能性。
【讨论】:
以上是关于Oracle PL SQL:比较两个存储过程返回的引用游标结果的主要内容,如果未能解决你的问题,请参考以下文章