2011-03-07 120 views
3

我想创建一个BEFORE INSERT触发,将检查字段的输入值,而在另一行具有相同的字段替换它,如果该字段为空。但是,当我将CALL语句添加到我的触发器时,将返回错误“The trigger "ORGSTRUCT.CSTCNTR_IN" is defined with an unsupported triggered SQL statement”。我查看了文档,发现在BEFORE(首先制作存储过程的部分原因)中不支持游标,但即使我从存储过程中删除了游标声明,该调用仍会生成相同的错误。BEFORE INSERT触发器和存储过程调用(DB2 LUW 9.5)

触发:

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 

根据该文件,CALL被允许在BEFORE触发,所以我不明白是什么问题。

回答

2

触发器之前可以调用存储过程,但存储的过程不能做任何触发器中不允许的操作。

在你的情况下,对SQL存储过程数据访问的默认级别为MODIFIES SQL DATA,这是不是在允许的触发。您可以重新创建存储过程,将数据访问级别更改为READS SQL DATA;这将允许您创建触发器。

但是:没有理由为这种简单的事情调用存储过程;您可以使用一个简单的在线触发做到这一点:

create trigger orgstruct.cstcntr_IN 
    no cascade 
    before insert on orgstruct.tOrgs 
    referencing new as r 
    for each row 
    mode db2sql 
    set r.cstcntr = case 
        when r.p_prnt is not null 
         then (select cstcntr from tOrgs where id = r.p_prnt fetch first 1 row only) 
        else r.cstcntr 
        end; 

这将是一个有效率,因为它消除了两个存储过程调用和存储过程中的游标处理。即使你想使用存储过程,也可以消除存储过程中的光标并提高性能。

FYI:您发布的逻辑包含一个错误,而且将永远设置CSTCNTR为NULL。在这个答案发布的触发器不这样做。 :-)