PLSQL Oracle触发器,按id对行中的金额求和
我有这样的桌子:PLSQL Oracle触发器,按id对行中的金额求和,sql,oracle,plsql,database-trigger,Sql,Oracle,Plsql,Database Trigger,我有这样的桌子: create or replace trigger trg_producers BEFORE INSERT OR DELETE OR UPDATE ON producers FOR EACH ROW declare pragma autonomous_transaction; producerShippedAmount number(10):=0; begin SELECT SUM(amount) INTO producerShippedAmount
create or replace trigger trg_producers
BEFORE INSERT OR DELETE OR UPDATE
ON producers
FOR EACH ROW
declare
pragma autonomous_transaction;
producerShippedAmount number(10):=0;
begin
SELECT SUM(amount) INTO producerShippedAmount
FROM Shippings
WHERE ProducernName = :NEW.Name;
:new.amount := producerShippedAmount;
end trg_producers;
发货表:
ProducernName| ... |Amount
A |... |1
B |... |2
A |... |5
C |... |3
C |... |5
ProducernName| ... |Amount
A |... |1
B |... |2
A |... |5
C |... |3
C |... |5
和另一张生产商表:
Name|...| Shipped Amount
A |...| NULL
B |...| NULL
C |...| NULL
Name|...| Amount
A |...| NULL
B |...| NULL
C |...| NULL
其思想是创建一个触发器,对每个生产商的Shippings表中的发货量求和,并在任何更改(更新、删除、插入)后在生产商表中进行更新
如果触发器工作,则Producers表将如下所示:
Name|...| Shipped Amount
A |...| 6
B |...| 2
C |...| 8
我试图找到金额的总和,并将其保存在我声明的变量中,但我不知道我的思维方向是否正确,以及如何将总和插入表中的正确行
CREATE TRIGGER SumShippedTrigger
AFTER INSERT OR DELETE OR UPDATE
OF amount
ON SHIPPINGS
FOR EACH ROW
DECLARE
producerShippedAmount NUMBER(10);
producer VARCHAR2(10);
BEGIN
SELECT SUM(amount) INTO producerShippedAmount
FROM Shippings
WHERE producer= :NEW.producer;
producer:= :NEW.procuder;
END;
/
如果有人能帮助我,我会很感激的!:) 为什么要为此使用触发器?数据是否太大,无法进行简单的汇总:
select producer, sum(amount)
from shippings
group by producer;
您可以很容易地为单个制作人查找此内容(使用where
),并使用索引使其更高效
如果您使用触发器,我会说,通常情况下,方法是增量更改总和:
CREATE TRIGGER SumShippedTrigger
AFTER INSERT OR DELETE OR UPDATE OF amount
ON SHIPPINGS
FOR EACH ROW
BEGIN
UPDATE producers
SET amount = COALESCE(amount, 0) + COALESCE(:new.amount, 0) - COALESCE(:old.amount, 0)
WHERE producer = COALESCE(:NEW.producer, :OLD.producer);
END;
虽然您的方法在逻辑上是正确的,但它所做的工作超出了必要的范围,可能会导致表触发器错误。为了查看以下表: 发货表:
ProducernName| ... |Amount
A |... |1
B |... |2
A |... |5
C |... |3
C |... |5
ProducernName| ... |Amount
A |... |1
B |... |2
A |... |5
C |... |3
C |... |5
另一张表是生产者:
Name|...| Shipped Amount
A |...| NULL
B |...| NULL
C |...| NULL
Name|...| Amount
A |...| NULL
B |...| NULL
C |...| NULL
您可以在producers
表中声明触发器,如下所示:
create or replace trigger trg_producers
BEFORE INSERT OR DELETE OR UPDATE
ON producers
FOR EACH ROW
declare
pragma autonomous_transaction;
producerShippedAmount number(10):=0;
begin
SELECT SUM(amount) INTO producerShippedAmount
FROM Shippings
WHERE ProducernName = :NEW.Name;
:new.amount := producerShippedAmount;
end trg_producers;
有必要提及的是,必须声明pragma autonomy_事务需要对@Gordon代码稍作修改。触发器触发DELETE,然后:new。是空的。因此where子句也需要与它们结合起来。“WHERE producer=coalesce(:NEW.producer;:Old.producer)@Belayer…很好的捕获。谢谢。非常感谢您的回复!但是我尝试了您的方法,但Producers表中我的amount行没有任何更改(将所有值插入表中后仍然为null)@Ian…这似乎有点问题。如果名称匹配,那么值至少应该更改为
0
,而不是NULL
。听起来好像没有调用触发器。或者,匹配条件没有产生实际的匹配。@Ian:您提交了更改吗?设计规则#2749:不存储摘要数据。您将在你职业生涯的剩余时间里,找出错误的原因。相反,在你需要的时候总结数据-然后它会是正确的,至少是暂时的。当我们对他们所拥有的表执行DML时触发。此触发器仅在生产者记录更改时更新生产者.AMOUNT。这显然不是OP的意图:他们想要更新SHIPPERS表更新时的PRODUCERS表。好的,这种方法是正确的,以便将PRODUCERS表更改为SHIPPERS表的更改,因此哪种方法适合您取决于您的业务,即使您可以在不使用触发器的情况下达到目标。我建议您可以在服务器端使用触发器进行处理。使用trigger不是合适的解决方案当你说“服务器端”是什么意思?数据库服务器可以被视为“服务器端”,那么你的建议是什么?