2017-06-07 89 views
-1

寫在表一個觸發器,它在Oracle 觸發器拋出突變表誤差更新另一個表。 我知道錯誤即將到來,因爲我正在更新在我的行級別塊參考的表,但我無法找出解決方法PL/SQL觸發器變異表上化合物觸發

編輯:此代碼拋出PL/SQL:數值或值錯誤:NULL索引表鍵值,但我似乎已經得到了變異表。

create or replace TRIGGER DSPLATE_WELL_VOLUME_V3 
FOR UPDATE ON DSPLATE 
COMPOUND TRIGGER 


TYPE t_PLATE_ID IS TABLE OF DSPLATE.PLATE_ID%TYPE; 
v_PLATE_ID t_PLATE_ID; 
TYPE t_NEW_AMOUNT IS TABLE OF DSPLATE.AMOUNT%TYPE; 
v_NEW_AMOUNT t_NEW_AMOUNT; 


BEFORE STATEMENT IS 
BEGIN 
    v_PLATE_ID := t_PLATE_ID(); 
    v_NEW_AMOUNT := t_NEW_AMOUNT(); 
END BEFORE STATEMENT; 


BEFORE EACH ROW IS 
BEGIN 
    IF :NEW.PLATE_TYPE != :OLD.PLATE_TYPE AND :NEW.PLATE_TYPE = 'Assay Plate' 
     AND :NEW.AMOUNT_INITIAL IS NOT NULL AND :OLD.AMOUNT_INITIAL IS NULL THEN 
      v_PLATE_ID(v_PLATE_ID.LAST) := :OLD.PLATE_ID; 
      v_NEW_AMOUNT(v_NEW_AMOUNT.LAST) := :NEW.AMOUNT_INITIAL; 
    END IF; 
END BEFORE EACH ROW; 

AFTER STATEMENT IS 
BEGIN 
    FOR p IN 1..v_PLATE_ID.LAST LOOP 
        UPDATE DSPLATE_WELL 
      SET AMOUNT = AMOUNT - v_NEW_AMOUNT(p) 
       WHERE WELL_ID IN (SELECT DSPLATE_WELL.WELL_ID 
       FROM DSPLATE INNER JOIN DSPLATE_WELL ON DSPLATE_WELL.PLATE_ID = DSPLATE.PLATE_ID 
       WHERE DSPLATE_WELL.WELL_VALUE IN (SELECT DSPLATE_WELL.WELL_VALUE 
       FROM DSPLATE_WELL INNER JOIN DSPLATE ON DSPLATE.PLATE_ID = DSPLATE_WELL.PLATE_ID WHERE DSPLATE.PLATE_ID = v_PLATE_ID(p)) 
       AND DSPLATE.PLATE_TYPE = 'Cherry Pick Plate' AND DSPLATE.LOCATION_ID = 1420); 
     END LOOP; 
END AFTER STATEMENT; 


END; 

原觸發我寫的工作是這樣的,但我希望它寫成複合觸發器相反,當plate_type被設置爲「測定板」的查詢查找在表plate_id的所有well_values DSPLATE_WELL的well_values對應回與plate_type「櫻桃挑選」和具體WELL_IDs表DSPLATE許多不同plate_ids其中WELL_VALUES最初來自必然有其容積量更新。

create or replace TRIGGER INSERT_DSPLATE_WELL_VOLUME 
AFTER UPDATE ON DSPLATE 
FOR EACH ROW 
DECLARE 
pragma autonomous_transaction; 


BEGIN 
    IF :NEW.PLATE_TYPE != :OLD.PLATE_TYPE AND :NEW.PLATE_TYPE = 'Assay Plate' 
AND :NEW.AMOUNT_INITIAL IS NOT NULL AND :OLD.AMOUNT_INITIAL IS NULL 
    THEN 
     UPDATE DSPLATE_WELL 
     SET AMOUNT = AMOUNT - :NEW.AMOUNT_INITIAL 
      WHERE WELL_ID IN (SELECT DSPLATE_WELL.WELL_ID 
      FROM DSPLATE INNER JOIN DSPLATE_WELL ON DSPLATE_WELL.PLATE_ID = DSPLATE.PLATE_ID 
      WHERE DSPLATE_WELL.WELL_VALUE IN (SELECT DSPLATE_WELL.WELL_VALUE 
      FROM DSPLATE_WELL INNER JOIN DSPLATE ON DSPLATE.PLATE_ID = DSPLATE_WELL.PLATE_ID WHERE DSPLATE.PLATE_ID = :OLD.PLATE_ID) 
      AND DSPLATE.PLATE_TYPE = 'Cherry Pick Plate' AND DSPLATE.LOCATION_ID = 1420); 
      COMMIT; 
    END IF; 
END; 
+0

我無法立即看到代碼是從什麼意思上看(無格式)的代碼。爲什麼在更新時需要查詢表格? –

+0

我解釋代碼是如何工作的在我的編輯 –

回答

0
create or replace TRIGGER DSPLATE_WELL_VOLUME_V3 
FOR UPDATE ON DSPLATE 
COMPOUND TRIGGER 



TYPE t_PLATE_ID IS TABLE OF DSPLATE.PLATE_ID%TYPE INDEX BY PLS_INTEGER; 
v_PLATE_ID t_PLATE_ID; 
v_NEW_AMOUNT t_PLATE_ID; 

counter number := 1; 


BEFORE EACH ROW IS 
BEGIN 
    IF :NEW.PLATE_TYPE != :OLD.PLATE_TYPE AND :NEW.PLATE_TYPE = 'Assay Plate' 
     AND :NEW.AMOUNT_INITIAL IS NOT NULL AND :OLD.AMOUNT_INITIAL IS NULL THEN 
      v_PLATE_ID(counter) := :OLD.PLATE_ID; 
      v_NEW_AMOUNT(counter) := :NEW.AMOUNT_INITIAL; 
      counter := counter + 1; 
    END IF; 
END BEFORE EACH ROW; 

AFTER STATEMENT IS 
BEGIN 
    FOR p IN 1..v_PLATE_ID.COUNT LOOP 
        UPDATE DSPLATE_WELL 
      SET AMOUNT = AMOUNT - v_NEW_AMOUNT(p) 
       WHERE WELL_ID IN (SELECT DSPLATE_WELL.WELL_ID 
       FROM DSPLATE INNER JOIN DSPLATE_WELL ON DSPLATE_WELL.PLATE_ID = DSPLATE.PLATE_ID 
       WHERE DSPLATE_WELL.WELL_VALUE IN (SELECT DSPLATE_WELL.WELL_VALUE 
       FROM DSPLATE_WELL INNER JOIN DSPLATE ON DSPLATE.PLATE_ID = DSPLATE_WELL.PLATE_ID WHERE DSPLATE.PLATE_ID = v_PLATE_ID(p)) 
       AND DSPLATE.PLATE_TYPE = 'Cherry Pick Plate' AND DSPLATE.LOCATION_ID = 1420 AND DSPLATE_WELL.AMOUNT IS NOT NULL); 
     END LOOP; 
END AFTER STATEMENT; 


END; 
1

你的觸發器應該是這樣的一個:

create or replace TRIGGER DSPLATE_WELL_VOLUME_V2 
FOR UPDATE ON DSPLATE 
COMPOUND TRIGGER 

TYPE t_WELL_ID IS TABLE OF DSPLATE_WELL.WELL_ID%TYPE; 
v_WELL_ID t_WELL_ID := t_WELL_ID(); 
TYPE t_AMOUNT IS TABLE OF INT; 
v_NEW_AMOUNT t_AMOUNT := t_AMOUNT(); 



TYPE t_PLATE_ID IS TABLE OF DSPLATE.PLATE_ID%TYPE; 
v_PLATE_ID t_PLATE_ID; 


BEFORE STATEMENT IS 
BEGIN 
    v_PLATE_ID := t_PLATE_ID(); 
END BEFORE STATEMENT; 


BEFORE EACH ROW IS 
BEGIN 
    IF :NEW.PLATE_TYPE != :OLD.PLATE_TYPE AND :NEW.PLATE_TYPE = 'Assay Plate' 
     AND :NEW.AMOUNT_INITIAL IS NOT NULL AND :OLD.AMOUNT_INITIAL IS NULL THEN 
      v_PLATE_ID.EXTEND; 
      v_PLATE_ID(v_PLATE_ID.LAST) := :OLD.PLATE_ID; 
    END IF; 
END BEFORE EACH ROW; 

AFTER STATEMENT IS 
BEGIN 

FOR p IN 1..v_PLATE_ID.LAST LOOP 

    SELECT DSPLATE_WELL.WELL_ID, :NEW.AMOUNT 
    BULK COLLECT INTO v_WELL_ID, v_NEW_AMOUNT 
    FROM DSPLATE INNER JOIN DSPLATE_WELL ON DSPLATE_WELL.PLATE_ID = DSPLATE.PLATE_ID 
    WHERE DSPLATE_WELL.WELL_VALUE IN 
      (SELECT DSPLATE_WELL.WELL_VALUE 
      FROM DSPLATE_WELL INNER JOIN DSPLATE ON DSPLATE.PLATE_ID = DSPLATE_WELL.PLATE_ID 
      WHERE DSPLATE.PLATE_ID = v_PLATE_ID(p)) 
     AND DSPLATE.PLATE_TYPE = 'Cherry Pick Plate' 
     AND DSPLATE.LOCATION_ID = 1420; 

    FOR i in 1..v_WELL_ID.count() LOOP 
     UPDATE DSPLATE_WELL SET AMOUNT = (AMOUNT - v_NEW_AMOUNT(i)) 
     WHERE WELL_ID = v_WELL_ID(i); 
    END LOOP; 

END LOOP; 


END AFTER STATEMENT; 

END; 

請注意,這段代碼沒有進行測試,最有可能在性能方面不是最優的(我假設第二個循環是不需要的,可放入一個UPDATE語句)。但是,您應該瞭解複合觸發器是如何工作的。

+0

我看你要去的方向,但這仍含有:在語句級新的綁定,這將引發在編譯的時候綁定錯誤 –

0

我寫類似化合物觸發器和我使用的「語句之前」趕上值(I曾用一個SELECT來填充塊狀的結構收集)和「每行後」進行更新。