我正在尝试学习如何创建用户定义的聚合函数。到目前为止,我已经能够创建一个编译良好的程序,但是调用它会产生意想不到的结果。该函数是一个非常简单的测试函数,它查看许多设置为“Y”或“N”的行,如果全部设置为“Y”则返回“Y”,否则返回“N”。我在单行上运行它并取回一个空白的 varchar 2 。
我不确定调试它的过程是什么。我尝试使用 DBMS_OUTPUT.PUT_LINE(),但在数据库输出中看不到任何内容。最大的问题是它创建的函数很好,而且大部分代码都是对象类型。因此,如果我要尝试调试 select 语句,它会调用已编译的数据库上的代码。
下面是该函数的代码,但我不想知道为什么它不能像我想知道如何调试那样工作,所以我可以自己解决这些问题,尤其是在涉及更复杂的聚合函数时。
CREATE OR REPLACE TYPE MYSCHEMA.ALL_TRUE_T AS OBJECT
(
TRUE_SO_FAR VARCHAR2(1),
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT ALL_TRUE_T) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(self IN ALL_TRUE_T, returnValue OUT VARCHAR2, flags IN NUMBER) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT ALL_TRUE_T, ctx2 IN ALL_TRUE_T) RETURN NUMBER
);
CREATE OR REPLACE TYPE BODY MYSCHEMA.ALL_TRUE_T IS
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT ALL_TRUE_T)
RETURN NUMBER IS
BEGIN
sctx := ALL_TRUE_T('Y');
return ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2)
RETURN NUMBER IS
BEGIN
IF value <> 'Y' OR self.TRUE_SO_FAR <> 'Y' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(self IN ALL_TRUE_T, returnValue OUT VARCHAR2, flags IN NUMBER)
RETURN NUMBER IS
BEGIN
returnValue := self.TRUE_SO_FAR;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT ALL_TRUE_T, ctx2 IN ALL_TRUE_T)
RETURN NUMBER IS
BEGIN
IF ctx2.TRUE_SO_FAR = 'N' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
END;
CREATE OR REPLACE PACKAGE MYSCHEMA.ALL_TRUE_PKG IS
FUNCTION ALL_TRUE (input VARCHAR2) RETURN VARCHAR2;
END;
CREATE OR REPLACE PACKAGE BODY MYSCHEMA.ALL_TRUE_PKG IS
FUNCTION ALL_TRUE (input VARCHAR2) RETURN VARCHAR2
AGGREGATE USING ALL_TRUE_T;
END;
这就是我所说的。YN_TEST_TABLE 当前只有一行,其中包含“N”。
SELECT
MYSCHEMA.ALL_TRUE_PKG.ALL_TRUE(YN)
FROM
MYSCHEMA.YN_TEST_TABLE
最后,我不确定这是否相关,但我使用的是 Toad 11.6。
编辑:
所以我尝试插入临时日志表,但也没有用。
我添加了以下内容
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2)
RETURN NUMBER IS
BEGIN
BEGIN
INSERT INTO MYSCHEMA.LAWTONFOGLES_TEMP_LOG
(
ID,
Message,
Time
)
VALUES
(
'all_true',
'test1',
systimestamp
);
END;
IF value <> 'Y' OR self.TRUE_SO_FAR <> 'Y' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
临时日志中没有任何内容,但也没有错误消息。就好像 4 个聚合函数部分都没有被调用。
编辑2:
所以,为了让事情变得更有趣,当它不在包中时,它可以工作。
我做了以下
CREATE OR REPLACE FUNCTION MYSCHEMA.LAWTONFOGLES_ALL_TRUE (input VARCHAR2) RETURN VARCHAR2
AGGREGATE USING ALL_TRUE_T;
然后运行这个
SELECT
MYSCHEMA.LAWTONFOGLES_ALL_TRUE(YN)
FROM
MYSCHEMA.YN_TEST_TABLE
并得到了我预期的结果。似乎代码本身没有问题,但是将其放入包中会导致其损坏。星期四,我的 Oracle DBA 将向 oracle 开票,所以我一定会更新为什么将它放在一个包中会破坏它,但当他们回来时将它作为一个函数保留并不会。在那之前,我可能只需要把它放在包裹外面。
另外,我尝试在它工作时在其上添加一个 put_line,但仍然没有得到输出。我认为用户定义的聚合函数的工作方式会阻止 put_line 工作。