【问题标题】:Trigger function to UPDATE a column up on INSERT在 INSERT 上更新列的触发函数
【发布时间】:2019-03-28 12:57:17
【问题描述】:

我想为 postgresql 表设置一个触发器函数,它应该使用从另一列派生的数据更新一列。

表:

CREATE TABLE day (
symbol varchar(20) REFERENCES another_table(symbol),
date date,
open NUMERIC(8,2),
high NUMERIC(8,2),
low  NUMERIC(8,2),
close NUMERIC(8,2),
sma8 NUMERIC(8,2),
PRIMARY KEY(symbol, date));

注意:复合主键。

样本插入:

INSERT INTO day VALUES('ABC', '2019-03-19', 102.3, 110.0, 125.3, 120.4, 0);
INSERT INTO day VALUES('ABC', '2019-03-20', 112.3, 109.0, 119.3, 118.4, 0);
INSERT INTO day VALUES('DEF', '2019-03-19', 1112.3, 1100.0, 1155.3, 1120.4, 0);
INSERT INTO day VALUES('DEF', '2019-03-20', 1202.3, 1180.0, 1205.3, 1190.4, 0);

等等。

当“日期”列是唯一的主键并且表仅包含与一个“符号”相关的数据(即表包含不同唯一日期的一个特定符号的数据)时,以下触发函数可以正常工作。

create or replace function update_sma8() RETURNS TRIGGER AS
$$
 BEGIN

 UPDATE day d SET sma8 = s.simple_mov_avg 
 FROM
 (
  SELECT  sec.date,AVG(sec.close)  
    OVER(ORDER BY sec.date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
     simple_mov_avg FROM day sec
 )s where s.date = NEW.date  --The newly inserted date
      AND d.date = s.date;   
 RETURN NULL;

 END $$ language plpgsql;

参考:SQL trigger function to UPDATE daily moving average upon INSERT

我想用通过平均当前'close'值和一个特定符号的最后7个'close'值得出的值更新'sma8'列('date'变化,即过去的数据。)。其他符号也是如此。

请指导我。谢谢。

【问题讨论】:

  • 存储可以计算的东西通常是个坏主意。它引入可能性,例如不正确,如果您按需运行计算,则不存在这些可能性。

标签: sql postgresql


【解决方案1】:

您需要知道如何按“符号”过滤行。

  1. 添加 WHERE 子句进行过滤。
WHERE sec.symbol = NEW.symbol
  1. 然后,您注册触发器。
CREATE TRIGGER day_insert
    AFTER INSERT ON day
    FOR EACH ROW
    EXECUTE PROCEDURE update_sma8();
  1. 确保在插入行时更新“sma8”列。

这是完整的代码。


DROP FUNCTION public.update_sma8();

CREATE FUNCTION public.update_sma8()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF 
AS $BODY$
 BEGIN

 UPDATE day d SET sma8 = s.simple_mov_avg 
 FROM
 (
  SELECT  sec.date,AVG(sec.close)  
    OVER(ORDER BY sec.date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
     simple_mov_avg FROM day sec WHERE symbol = NEW.symbol
 )s where s.date = NEW.date  --The newly inserted date
      AND d.date = s.date ;   
 RETURN NULL;

 END $BODY$;

ALTER FUNCTION public.update_sma8()
    OWNER TO postgres;

【讨论】:

    【解决方案2】:

    您可以添加PARTITION BY symbol,然后在where 子句中使用它来计算每个符号。

    create or replace function update_sma8() RETURNS TRIGGER AS
    $$
     BEGIN
    
     UPDATE day d SET sma8 = s.simple_mov_avg 
     FROM
     (
      SELECT  sec.date,sec.symbol,AVG(sec.close)  
        OVER( partition by symbol ORDER BY sec.date ROWS BETWEEN 
                              7 PRECEDING AND CURRENT ROW) AS 
         simple_mov_avg FROM day sec
     )s where s.date = NEW.date  --The newly inserted date
          AND d.date = s.date   
          AND d.symbol = s.symbol;
      RETURN NULL;
     END $$ language plpgsql;
    

    DEMO

    【讨论】:

    • 检查执行计划。使用 PARTION-BY 的成本比上面的答案要贵。
    • 是的,你是对的,我忽略了它。 @selva:请考虑使用 Ahn Dennis 的答案。
    • @KaushikNayak,谢谢你,先生。我正在评估选择哪个答案,现在我将选择 Ahn Dennis 先生的答案。
    猜你喜欢
    • 2011-07-07
    • 2020-08-16
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多