2009-05-26 20 views
4

我該如何解決Oracle在觸發器中不允許子查詢的限制。Oracle:在觸發器中使用子查詢

下面是我試圖創建的示例觸發器,但無法使用,因爲我無法使用子查詢。

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1 
    AND (SELECT offer FROM projects WHERE projnum = :new.projnum) IS NULL 
) 
BEGIN 
    INSERT INTO offer_log (offer, status, date) 
    VALUES (null, 9, sysdate); 
END; 

回答

9

該觸發器將做到這一點:

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1 
) 
DECLARE 
    l_offer projects.offer%TYPE; 
BEGIN 
    SELECT offer INTO l_offer 
    FROM projects 
    WHERE projnum = :new.projnum; 

    IF l_offer IS NULL THEN 
    INSERT INTO offer_log (offer, status, date) 
    VALUES (null, 9, sysdate); 
    END IF; 
END; 

我假設從項目中選擇將始終找到一行;如果不是,它會引發一個NO_DATA_FOUND異常,您可能需要處理。

2

你可以把條件放入動作(在BEGIN和END之間),而不是在'是否觸發'?是的,這意味着觸發的身體可能更頻繁地解僱 - 但如果它讓你解決問題...

+3

執行子查詢的代價很可能遠高於觸發觸發器的開銷,所以我猜這無關緊要。 – 2009-05-26 06:29:06

+0

嘗試開始如果(SELECT offer FROM projects where projnum =:new.projnum)IS NULL THEN INSERT INTO等等。但是,它會在遇到SELECT語句時拋出一個錯誤。它只是不指望它。 – vipirtti 2009-05-26 06:33:04

+0

我對PL/SQL不太熟悉,不知道這是否是在觸發器中編寫代碼的合理方式。看上去不錯;我知道的其他系統需要從SELECT(使用INTO子句和變量)進行某種分配,然後檢查該變量,或沿着這些行。有可能描述手冊中觸發器的限制。另外 - 你可以在動作部分調用一個過程嗎?如果是這樣,也許這會對你有用? (將相關值作爲參數傳遞。) – 2009-05-26 06:40:48

4

我希望你想要的東西像

CREATE OR REPLACE TRIGGER trigger_w_subquery 
AFTER UPDATE OR INSERT ON project_archiving 
FOR EACH ROW 
WHEN (old.archiving_status <> new.archiving_status 
    AND new.archiving_status = 1) 
DECLARE 
    l_offer projects.offer%TYPE; 
BEGIN 
    SELECT offer 
    INTO l_offer 
    FROM projects 
    WHERE projnum = :new.projnum; 

    IF(l_offer IS NULL) 
    THEN 
    INSERT INTO offer_log (offer, status, date) 
     VALUES (null, 9, sysdate); 
    END IF; 
END;