我有一个条件,我需要用e1、e2和e3的值更新表x1。假设e1是主键。当X2上的数据被修改时,我需要拉取e2的最大值和e3的最大值来更新表X1。我写了这样的触发器,但是得到了变异表错误。我不想使用PRAGMA自治事务。您的帮助将是appriciated。
create or replace TRIGGER TR_UPDATE_ON_X2
AFTER INSERT OR UPDATE OR DELETE ON X2
FOR EACH ROW
DECLARE
cnt NUMBER;
E1 VARCHAR2(20 BYTE);
E2 NUMBER(3,0);
E3 VARCHAR2(50 BYTE);
BEGIN
IF INSERTING OR UPDATING THEN
SELECT COUNT(1) INTO CNT FROM X1 WHERE E1 = :NEW.E1;
IF(CNT =0)THEN
INSERT INTO X1 (E1, E2, E3) VALUES(:NEW.E1,:NEW.E2,:NEW.E3);
ELSE
SELECT E1,E2,E3 INTO E1, E2, E3 FROM X1 WHERE E1 = :NEW.E1;
IF(:NEW.E1 > E1) THEN
E1 := :NEW.E1;
END IF;
IF(:NEW.E2 > E2) THEN
E2 := :NEW.E2;
END IF;
IF(:NEW.E3 > E3) THEN
E3 := :NEW.E3;
END IF;
UPDATE X1 SET E1 = E1, E2 = E2, E3 = E3 WHERE E1 = :NEW.E1;
END IF;
ELSIF DELETING THEN
SELECT COUNT(1) INTO CNT FROM X2 WHERE CONTRACTORSOIDENTIFIER = :NEW.CONTRACTORSOIDENTIFIER;
IF(CNT != 0)THEN
SELECT E1,MAX(E2),MAX(E3) INTO E1, E2, E3 FROM X2 WHERE E1 = :NEW.E1 GROUP BY X2.E1;
IF(:NEW.E1 > E1) THEN
E1 := :NEW.E1;
END IF;
IF(:NEW.E2 > E2) THEN
E2 := :NEW.E2;
END IF;
IF(:NEW.E3 > E3) THEN
E3 := :NEW.E3;
END IF;
UPDATE X1 SET E1 = E1, E2 = E2, E3 = E3 WHERE E1 = :NEW.E1;
ELSE
DELETE FROM X1 WHERE E1 = :NEW.E1;
END IF;
END IF;
END;
1条答案
按热度按时间nle07wnf1#
因此,x2中每个e1可以有许多行。对于x2中存在的每个e1,x1中存在一行。x1行包含每个e1的e2和e3的最大值。
INSERTING OR UPDATING
部分看起来不错,除了变量的名称与列相同。正如William Robertson在请求注解中指出的,SET E1 = E1
只是意味着保持值不变。DBMS不会猜测第二个E1应该是另一个E1。通常在变量前面加上v_,以使它们与列名不同。您的
DELETING
有一个主要问题,即删除一个x2行后,必须重新计算e1的x1最大值,这意味着我们必须在表发生变化时从x2中进行选择。(由于delete语句可以影响多行,因此AFTER ROW
不一定表示AFTER STATEMENT
,因此,我们可能正处于变化之中,无法确定地说哪些还在表中,哪些还没有。)这个问题的解决方案是复合触发器。这种触发器类型结合了before/after row和before/after statement。因此,您可以查看行,查看哪些e1受到影响,然后在处理完所有行后,为所有受影响的e1更新x1。
下面是一个简单的触发器(当然还有优化的空间:-)