包含子查询的SQL触发器可能吗?

时间:2014-09-06 05:21:24

标签: sql oracle triggers subquery

会感激一些帮助;我正在使用Oracle。

当前代码:

CREATE OR REPLACE TRIGGER TRG_SAMPLETRG
BEFORE INSERT ON CATEGORY_Details
FOR EACH ROW
DECLARE W_YEARSALIVE NUMBER(3);
BEGIN

  SELECT ((SYSDATE - animal_origindate)/365) INTO W_YEARSALIVE
  FROM animal
  WHERE animal_no = :NEW.animal_no;

  IF W_YEARSALIVE < 180 THEN
    RAISE_APPLICATION_ERROR(-20005, 'The animal has existed for only ' || W_YEARSALIVE || ' years');
  ELSIF W_YEARSALIVE IS NULL THEN
    RAISE_APPLICATION_ERROR(-20005, 'The animal has to have a origin date entered before evaluation.');
  ELSE
    DBMS_OUTPUT.PUT_LINE ('The animal is over 180 years and is not yet extinct and has been added');
  END IF;
END;

当我将动物添加到category_details表中时,如果动物的原始日期(以年为单位)小于180,或者如果它没有原始日期,则不会添加动物并且异常错误将被退回。

现在,我不需要在我插入category_details表的每只动物上评估触发器,我只想从这些不同类别中的4个添加/评估动物的触发器:Monera,Prokaryota,Plantae,Eukaryota

即。 任何其他不同的类别,即Animalia,Vegetabilia,甚至根本不应进行评估,也就是说,不限制任何与那些(或其他类别)相关的动物插入。< /强>

我尝试使用如下子查询添加WHEN语句:     WHEN(:NEW.kingdom_no IN(SELECT kingdom_no FROM kingdom WHERE kingdom_name IN(&#39; Monera&#39;,&#39; Prokaryota&#39;,&#39; Plantae&#39;,&#39; Eukaryota&#39; ;))

但看起来您无法将子查询添加到TRIGGERS ...

我找到了这个帖子:Oracle: Using subquery in a trigger

然而,似乎只有1个值/类别看起来整洁,而我有4个,并且必须声明4个变量?

我还试图将子查询放在IF语句中,但我不认为它在SQL / Oracle中在语法上有效。

感谢您的任何帮助。

编辑:表结构很简单: 3个表:动物,category_details和王国 category_details&#39; table具有以下属性:animal_no,kingdom_no 动物&#39; table具有以下属性:animal_no,animal_origindate 王国&#39; table具有以下属性:kingdom_no,kingdom_name

2 个答案:

答案 0 :(得分:1)

根据Oracle文档 [WHEN]条件不能包含子查询,您必须将此部分放在触发器主体内,例如。

CREATE OR REPLACE TRIGGER trg_sampletrg
  BEFORE INSERT ON category_details
  FOR EACH ROW

DECLARE

  w_kingdom_name kingdom.kingdom_name%TYPE;
  w_yearsalive   NUMBER(3);

BEGIN

  SELECT kingdom_name
  INTO w_kingdom_name
  FROM kingdom
  WHERE kingdom_no = :new.kingdom_no;

  IF w_kingdom_name IN ('Monera', 'Prokaryota', 'Plantae', 'Eukaryota') THEN

    SELECT months_between(sysdate, animal_origindate)/12
    INTO w_yearsalive
    FROM animal
    WHERE animal_no = :new.animal_no;

    IF w_yearsalive < 180 THEN
      raise_application_error(-20005, 'The animal has existed for only ' || w_yearsalive || ' years');
    ELSIF w_yearsalive IS NULL THEN
      raise_application_error(-20005, 'The animal has to have a origin date entered before evaluation.');
    END IF;

  END IF;

END;

答案 1 :(得分:1)

您根本不能在PL / SQL中内联子查询。你能做的就是这样:

SELECT k.kingdom_name
INTO   l_kingdom
FROM   kingdom k
WHERE  k.kingdom_no = :NEW.kingdom_no;

IF l_kingdom in ('Monera','Prokaryota','Plantae','Eukaryota' THEN
   -- Do what needs to be done
END IF;

通常,您可以在行触发器中执行所需的所有DML(选择,更新,插入等)。经常惹恼别人的例外是你不能在连接触发器的桌子上做DML - 在你的情况下是CATEGORY_DETAILS。