【问题标题】:SQL trigger function to UPDATE daily moving average upon INSERTSQL 触发函数在 INSERT 时更新每日移动平均线
【发布时间】:2019-06-05 11:18:53
【问题描述】:

我正在尝试创建一个 SQL 触发器函数,该函数应该在将数据插入到表中时更新列。更新基于正在插入的值中存在的值。

我有下表来存储股票的每日 OHLC 数据。

CREATE TABLE daily_ohlc (
 cdate date,
 open numeric(8,2),
 high numeric(8,2),
 low numeric(8,2),
 close numeric(8,2),
 sma8 numeric(8,2)
);

插入命令:

INSERT INTO daily_ohlc (cdate, open, high, low, close) 
 values ('SYMBOL', 101, 110, 95, 108);

执行此命令时,我想根据正在插入的当前值和表中已有的值更新“sma8”列。

到目前为止,我正在使用以下 SQL 查询来计算每一行的值,然后使用结果来使用 python 更新“sma8”列。

SELECT sec.date, AVG(sec.close) 
 OVER(ORDER BY sec.date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS 
simple_mov_avg FROM daily_ohlc sec;

上述查询计算最近 8 条记录(包括当前行)的简单移动平均线。

使用此过程,我每次插入数据时都会更新“sma8”列中的每一行数据。我想通过使用触发器只更新最后一行(即插入的行)。如何做到这一点?

【问题讨论】:

  • 表的唯一键/主键是什么?.. 您如何将字母字符串 'SYMBOL' 插入日期列?
  • @KaushikNayak 这是我输入问题时的错误。问题中的 INSERT 命令应该是INSERT INTO daily_ohlc (cdate, open, high, low, close) values ('2019-01-10', 101, 110, 95, 108);
  • 那么,cdate 是表中的唯一列吗?
  • @KaushikNayak,是的 cdate 是主键(唯一)。

标签: sql postgresql triggers


【解决方案1】:

您可以在触发器中使用适当的联接来执行UPDATE FROM 选择查询。

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

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

END $$ language plpgsql;

Demo

使用此方法的唯一警告是,如果有人删除行或更新 close 列,则必须重新计算值,这不会发生在现有行上。只有插入的行会看到正确的重新计算值。

相反,您可以简单地创建 View 以在请求时从主表中为所有行计算 sma8 列。

【讨论】:

  • 谢谢。这真的帮助了我。除此之外,我还需要其他帮助。我需要为不同的表(相同的模式)执行相同的触发函数。怎么做?我尝试使用 TG_TABLE_NAME 代替 daily_ohlc(即表名),但没有成功。
  • @selvask。不客气。您应该考虑将其作为一个单独的问题提出,将此问题与详细信息联系起来。这回答了您最初的问题。
  • 我提出了一个与此相关的新问题。如果你有时间,请仔细研究一下。谢谢你。链接:[stackoverflow.com/questions/54159782/…
【解决方案2】:

你不能按照这些思路做点什么吗?

INSERT INTO daily_ohlc 
SELECT current_date, 101, 110, 95, 108, (COUNT(*)*AVG(close)+108)/(1+Count(*))
FROM daily_ohlc
WHERE cDate >= ANY (
    SELECT MIN(cdate)
    FROM (SELECT CDate, ROW_NUMBER() OVER (ORDER BY CDate DESC) as RowNum FROM daily_ohlc) a 
    WHERE RowNum <= 7
)

我很清楚,与触发器相比,它可能看起来很复杂。
但是,我试图避免您成功创建 ON INSERT 触发器并接下来要处理表中的更新的情况。在由同一表中的更新触发的过程中更新表并不是最好的主意。

【讨论】:

  • 'cdate' 包含日期(数据),并且不是连续的(但按递增顺序)可能有超过一天的缺失。所以'sma8'应该填充最后8个'close'的平均值(包括现在的)。
猜你喜欢
  • 2012-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-22
相关资源
最近更新 更多