2011-03-07 60 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。在這個答案發布的觸發器不這樣做。 :-)