【问题标题】:Trigger to update current date in Postgres 9触发在 Postgres 9 中更新当前日期
【发布时间】:2011-12-13 18:58:05
【问题描述】:

我有两个名为salecustomer 的表。我想创建一个触发器,在sale 表中的每个新插入上更新customer 表上的列last_purchase

表客户:customer_id、name、last_sale、...
表销售:sale_id、customer_id、日期、...

CREATE TRIGGER update_last_sale BEFORE INSERT ON sale FOR EACH ROW EXECUTE...

我已经开始写了,但我不知道怎么写。
有人可以帮我吗?

【问题讨论】:

    标签: sql database postgresql triggers


    【解决方案1】:
    CREATE FUNCTION update_customer_last_sale() RETURNS TRIGGER AS $$
    BEGIN
        UPDATE customer SET last_sale=now() WHERE cutomer_id=NEW.customer_id;
        RETURN NEW;
    END; $$
    LANGUAGE plpgsql;
    

    然后

    CREATE TRIGGER update_last_sale
    BEFORE INSERT ON sale
    FOR EACH ROW EXECUTE update_customer_last_sale;
    

    NEW 是即将插入到销售表中的行。 (对于更新行,NEW 表示更新后行的外观,OLD 表示更新前行的外观)。

    【讨论】:

    • 触发器创建不起作用,最后一行需要... FOR EACH ROW EXECUTE PROCEDURE update_customer_last_sale();至少对于 postgres 10.
    【解决方案2】:

    基本上,我认为存储冗余数据不是一个好主意。客户中的 last_sale 列只是 max(sales.sale_date) 的聚合。

    如果我们使用 now() 来访问 customers.last_date,情况会变得更糟。如果我们需要重新插入一些历史记录(例如重新计算去年的税收)会发生什么。这就是你存储冗余数据时得到的结果......

    -- modelled after Erwin's version
    SET search_path='tmp';
    
    -- DROP TABLE customers CASCADE;
    CREATE TABLE customers
        ( id INTEGER NOT NULL PRIMARY KEY
        , name VARCHAR
        , last_sale DATE
        );
    
    -- DROP TABLE sales CASCADE;
    CREATE TABLE sales
        ( id INTEGER NOT NULL PRIMARY KEY
        , customer_id INTEGER REFERENCES customers(id)
        , saledate DATE NOT NULL
        );
    
    
    CREATE OR REPLACE FUNCTION update_customer_last_sale() RETURNS TRIGGER AS $meat$
    BEGIN
        UPDATE customers cu
        -- SET last_sale = now() WHERE id=NEW.customer_id
        SET last_sale = (
            SELECT MAX(saledate) FROM sales sa
            WHERE sa.customer_id=cu.id
            )   
        WHERE cu.id=NEW.customer_id
        ;
        RETURN NEW;
    END; $meat$
    LANGUAGE plpgsql;
    
    CREATE TRIGGER update_last_sale
        AFTER INSERT ON sales
        FOR EACH ROW
        EXECUTE PROCEDURE update_customer_last_sale();
    
    
    INSERT INTO customers(id,name,last_sale) VALUES(1, 'Dick', NULL),(2, 'Sue', NULL),(3, 'Bill', NULL);
    
    
    INSERT INTO sales(id,customer_id,saledate) VALUES (1,1,'1900-01-01'),(2,1,'1950-01-01'),(3,2,'2011-12-15');
    
    SELECT * FROM customers;
    
    SELECT * FROM sales;
    

    结果:

     id | name | last_sale  
    ----+------+------------
      3 | Bill | 
      1 | Dick | 1950-01-01
      2 | Sue  | 2011-12-15
    (3 rows)
    
     id | customer_id |  saledate  
    ----+-------------+------------
      1 |           1 | 1900-01-01
      2 |           1 | 1950-01-01
      3 |           2 | 2011-12-15
    (3 rows)
    

    【讨论】:

      【解决方案3】:

      我想你想要这里的规则。

      CREATE RULE therule AS ON INSERT TO sale DO ALSO
          (UPDATE customer SET customer.last_sale = now()
                 WHERE customer.customer_id=NEW.customer_id);
      

      编辑:但请参阅 cmets 中的讨论。

      【讨论】:

      • 规则非常棘手,您必须非常了解它们才能正确使用它们。使用 COPY 插入数据时也不行!
      • @FrankHeikens,必须了解您使用的东西并不少见,我想说了解触发器也没有什么坏处;-)
      • 规则有些过时,Postgres 团队明确建议使用触发器。
      • @a_horse_with_no_name,愿意透露出处吗?
      • @MichaelKrelin-hacker:例如在关于CREATE RULE 的章节中:“如果你真的想要一个为每个物理行独立触发的操作,你可能想要使用触发器”。现在我们有了instead of 视图触发器,几乎没有任何理由使用它们。此外,它们也比触发器慢。看这里的最后一句话:postgresql.org/docs/current/static/rules-triggers.html
      猜你喜欢
      • 2014-02-19
      • 2010-10-03
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多