2009-05-26 95 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;