使用存储过程调用的 BEFORE INSERT 触发器 (DB2 LUW 9.5)
我正在尝试创建一个 BEFORE INSERT 触发器,该触发器将检查字段的传入值,如果该字段为空,则将其替换为另一行中的相同字段。但是,当我将 CALL
语句添加到触发器时,会返回错误“触发器“ORGSTRUCT.CSTCNTR_IN”是使用不受支持的触发 SQL 语句定义的
”。我检查了文档,发现之前不支持游标(首先创建存储过程的部分原因),但即使我从存储过程中删除游标声明,调用仍然会生成相同的错误。
触发器:
CREATE TRIGGER orgstruct.cstcntr_IN
NO CASCADE
BEFORE INSERT ON orgstruct.tOrgs
REFERENCING NEW AS r
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
DECLARE prnt_temp BIGINT;
DECLARE cstcntr_temp CHAR(11);
SET prnt_temp = r.prnt;
SET cstcntr_temp = r.cstcntr;
CALL orgstruct.trspGetPrntCstCntr(prnt_temp,cstcntr_temp);
SET r.cstcntr = cstcntr_temp;
END
存储过程:
CREATE PROCEDURE orgstruct.trspGetPrntCstCntr (
IN p_prnt BIGINT,
OUT p_cstcntr CHAR(11)
)
SPECIFIC trGetPrntCstCntr
BEGIN
IF p_prnt IS NULL THEN
RETURN;
END IF;
BEGIN
DECLARE c1 CURSOR
FOR
SELECT cstcntr
FROM orgstruct.tOrgs
WHERE id = p_prnt
FOR READ ONLY;
OPEN c1;
FETCH FROM c1 INTO p_cstcntr;
CLOSE c1;
END;
END
根据文档,BEFORE
触发器中允许CALL
,所以我不明白问题是什么。
I am trying to create a BEFORE INSERT
trigger that will check the incoming value of a field, and replace it with the same field in another row if that the field is null. However, when I add the CALL
statement to my trigger, an error is returned "The trigger "ORGSTRUCT.CSTCNTR_IN" is defined with an unsupported triggered SQL statement
". I checked the documentation and saw that cursors weren't supported in the BEFORE (part of the reason for making the stored procedure in the first place), but even when I remove the cursor declaration from the stored procedure the call still generates the same error.
Trigger:
CREATE TRIGGER orgstruct.cstcntr_IN
NO CASCADE
BEFORE INSERT ON orgstruct.tOrgs
REFERENCING NEW AS r
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
DECLARE prnt_temp BIGINT;
DECLARE cstcntr_temp CHAR(11);
SET prnt_temp = r.prnt;
SET cstcntr_temp = r.cstcntr;
CALL orgstruct.trspGetPrntCstCntr(prnt_temp,cstcntr_temp);
SET r.cstcntr = cstcntr_temp;
END
Stored procedure:
CREATE PROCEDURE orgstruct.trspGetPrntCstCntr (
IN p_prnt BIGINT,
OUT p_cstcntr CHAR(11)
)
SPECIFIC trGetPrntCstCntr
BEGIN
IF p_prnt IS NULL THEN
RETURN;
END IF;
BEGIN
DECLARE c1 CURSOR
FOR
SELECT cstcntr
FROM orgstruct.tOrgs
WHERE id = p_prnt
FOR READ ONLY;
OPEN c1;
FETCH FROM c1 INTO p_cstcntr;
CLOSE c1;
END;
END
According to the documentation, CALL
is allowed in a BEFORE
trigger, so I don't understand what the problem is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
before 触发器可以调用存储过程,但存储过程不能执行触发器中不允许的任何操作。
在您的情况下,SQL 存储过程的默认数据访问级别是 MODIFIES SQL DATA,这在触发器中是不允许的。您可以重新创建存储过程,将数据访问级别更改为“READS SQL DATA”;这将允许您创建触发器。
但是:没有理由为如此简单的事情调用存储过程;您可以使用简单的内联触发器来完成此操作:
这将更加高效,因为它消除了存储过程调用和存储过程内的游标处理。即使您想使用存储过程,也可以消除存储过程中的游标并提高性能。
仅供参考:您发布的逻辑包含错误,并且始终将 CSTCNTR 设置为 NULL。此答案中发布的触发器不会执行此操作。 :-)
A before trigger can call a stored procedure, but the stored proc can't do anything not allowed in the trigger.
In your case, the default level of data access for a SQL stored proc is
MODIFIES SQL DATA
, which is not allowed in the trigger. You could recreate your stored procedure, changing the data access level toREADS SQL DATA
; this will allow you to create the trigger.However: There is no reason to call a stored procedure for something this simple; You can do it using a simple inline trigger:
This will be a LOT more efficient because it eliminates both the stored procedure call and the cursor processing inside the stored proc. Even if you wanted to use the stored proc, you could eliminate the cursor inside the stored proc and improve performance.
FYI: the logic that you posted contains an error, and will always set CSTCNTR to NULL. The trigger posted in this answer not do this. :-)