【问题标题】:Trigger function updates all rows instead of one (PostgreSQL)触发函数更新所有行而不是一个(PostgreSQL)
【发布时间】:2016-06-07 16:59:41
【问题描述】:

使用 PostgreSQL。 我所拥有的是: 3 个表格

1.Customer2c 与列:CustomerID,PersonID,Number_Of_Items`。

2.SalesOrderHeader2c 与列:SalesOrderID,CustomerID

  1. SalesOrderDetail2c 与列:SalesOrderDetailID,SalesOrderID,OrderQty

我想创建一个触发函数,只要有人使用它就会触发

INSERT INTO 'SalesOrderDetail2c' table

这将获取插入的OrderQty 并用它更新对应的Number_Of_Items 字段。

我的触发器正在工作,但问题是每当我向 SalesOrderDetail2c 插入新值时,该函数都会获取OrderQty 值并更新Number_Of_Items 的所有行用它,而不是只更新对应的。

任何帮助表示赞赏。我目前的情况是这样的(可能完全错误,请不要判断!):

CREATE OR REPLACE FUNCTION FunctionTrigger2c() RETURNS TRIGGER AS
$BODY$
BEGIN
    UPDATE Customer2c
    SET Number_Of_Items = 
    (SELECT OrderQty
    FROM SalesOrderDetail2c
    INNER JOIN SalesOrderHeader2c ON (SalesOrderDetail2c.SalesOrderID = SalesOrderHeader2c.SalesOrderID)
    INNER JOIN Customer2c ON (SalesOrderHeader2c.CustomerID = Customer2c.CustomerID)
    ORDER BY SalesOrderDetailID DESC LIMIT 1
    )
    FROM SalesOrderHeader2c
    WHERE SalesOrderHeader2c.CustomerID = Customer2c.CustomerID
    ;
    RETURN NEW;
    END;
$BODY$ 
language plpgsql;

CREATE TRIGGER Trigger2c
     AFTER INSERT ON SalesOrderDetail2c
     FOR EACH ROW
     EXECUTE PROCEDURE FunctionTrigger2c();

【问题讨论】:

标签: sql postgresql triggers sql-update


【解决方案1】:

我不得不像上面提到的@Nicarus 一样使用 .new!再次感谢。

这是新代码,现在只更改对应的值。

CREATE OR REPLACE FUNCTION FunctionTrigger2c() RETURNS TRIGGER AS
$BODY$
BEGIN
    UPDATE Customer2c
    SET Number_Of_Items = 
    (SELECT new.OrderQty
    FROM SalesOrderDetail2c
    order by salesorderdetailid desc limit 1
    )
    FROM SalesOrderheader2c
    WHERE (SalesOrderheader2c.salesorderID = new.salesorderID) and (salesorderheader2c.customerid = customer2c.customerid)
    ;
    RETURN NEW;
    END;
$BODY$ 
language plpgsql;

CREATE TRIGGER Trigger2c
     AFTER INSERT ON SalesOrderDetail2c
     FOR EACH ROW
     EXECUTE PROCEDURE FunctionTrigger2c();

【讨论】:

  • 您似乎将Number_Of_Items 设置为最后添加的OrderQty SalesOrderDetail。不应该是 all SalesOrderDetails 的总和吗?请看我的回答。
【解决方案2】:

我指出为什么您的原始触发器不起作用。它更新每一行的原因是因为您的 UPDATE 语句。插入某些内容后,它会触发更新。 当更新运行时,它得到了这些东西:

  1. 我要更新什么表
  2. 我要在给定表的哪一列上设置什么值
  3. 我将在哪些行上实施此更新(FROM + WHERE)

问题出在最后一部分,基本上在 UPDATE 语句中调用 FROM 就像调用 SELECT 语句一样,它试图用给定的 WHERE 值处理 FROM 子句表中的每一行。

关于 UPDATE 语句 from_list 参数的 PostgreSQL 文档指出“A 表表达式列表,允许来自其他表的列 出现在 WHERE 条件和更新表达式中。这是 类似于可以在 FROM 子句中指定的表列表 一个 SELECT 语句。" (https://www.postgresql.org/docs/9.1/sql-update.html)

基本上,您的更新语句会遍历 SalesOrderHeader2c 中的每一行,这很容易与 Customer2c 的每一行匹配(SalesOrderHeader2c.CustomerID = Customer2c.CustomerID em>),使用 UPDATE SET 语句中第一个找到的 Number_Of_Items 值更新 Customer2c 中每一行的值。这就是为什么 Customer2c 中的每一行都得到相同值的原因。

新触发器起作用的原因是更新语句是使用正确选择的行完成的。

【讨论】:

    【解决方案3】:

    这是我的非常通用的触发器,用于在从属表中对值进行计数/求和。您应该注意所有订单更改,即不仅是INSERT,还要注意DELETEUPDATE。您还应该阅读@Nicarus 关于在触发器中使用NEW(和OLD)的评论。

    我已对其进行了更改以匹配您的架构,但没有对其进行测试...

    CREATE OR REPLACE FUNCTION FunctionTrigger2c()
      RETURNS trigger AS
    $BODY$
    DECLARE
    BEGIN
        CASE TG_OP
            WHEN 'INSERT' THEN
                UPDATE
                    Customer2c
                SET
                    Number_Of_Items = Number_Of_Items + NEW.OrderQty
                FROM
                    SalesOrderHeader2c
                WHERE
                    Customer2c.CustomerID = SalesOrderHeader2c.CustomerID AND
                    SalesOrderHeader2c.SalesOrderID = NEW.SalesOrderID AND
                    SalesOrderDetailID = NEW.SalesOrderDetailID;
    
            WHEN 'UPDATE' THEN
                UPDATE
                    Customer2c
                SET
                    Number_Of_Items = Number_Of_Items - OLD.OrderQty
                FROM
                    SalesOrderHeader2c
                WHERE
                    Customer2c.CustomerID = SalesOrderHeader2c.CustomerID AND
                    SalesOrderHeader2c.SalesOrderID = OLD.SalesOrderID AND
                    SalesOrderDetailID = OLD.SalesOrderDetailID;
    
                UPDATE
                    Customer2c
                SET
                    Number_Of_Items = Number_Of_Items + NEW.OrderQty
                FROM
                    SalesOrderHeader2c
                WHERE
                    Customer2c.CustomerID = SalesOrderHeader2c.CustomerID AND
                    SalesOrderHeader2c.SalesOrderID = NEW.SalesOrderID AND
                    SalesOrderDetailID = NEW.SalesOrderDetailID;
    
            WHEN 'DELETE' THEN
                UPDATE
                    Customer2c
                SET
                    Number_Of_Items = Number_Of_Items - OLD.OrderQty
                FROM
                    SalesOrderHeader2c
                WHERE
                    Customer2c.CustomerID = SalesOrderHeader2c.CustomerID AND
                    SalesOrderHeader2c.SalesOrderID = OLD.SalesOrderID AND
                    SalesOrderDetailID = OLD.SalesOrderDetailID;
        END CASE;
    
        RETURN NULL;
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    

    如果您更改SalesOrderIDUPDATE 也可以正常工作:)

    注意,这个触发器返回NULL,应该设置为AFTER INSERT OR UPDATE OR DELETE

    CREATE TRIGGER Trigger2c
      AFTER INSERT OR UPDATE OR DELETE
      ON SalesOrderDetail2c
      FOR EACH ROW
      EXECUTE PROCEDURE FunctionTrigger2c();
    

    【讨论】:

    • 你说得对,我忘了加上前面的值。并且您的架构更加灵活。但是,我的指示是仅针对 INSERT INTO 进行特定触发。
    猜你喜欢
    • 1970-01-01
    • 2021-09-08
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 2017-10-28
    相关资源
    最近更新 更多