PostgreSQL在插入不同表时更新相同的触发器函数(使用相同的模式)

PostgreSQL在插入不同表时更新相同的触发器函数(使用相同的模式),sql,postgresql,triggers,Sql,Postgresql,Triggers,我有100多个表具有相同的模式,并且我有一个触发器函数,每当数据插入到表中时,它都会更新某些列 表架构: CREATE TABLE symbol_daily_ohlc ( cdate date, open numeric(8,2), high numeric(8,2), low numeric(8,2), close numeric(8,2), sma8 numeric(8,2) ); 触发功能: create or replace function update_sma8() R

我有100多个表具有相同的模式,并且我有一个触发器函数,每当数据插入到表中时,它都会更新某些列

表架构:

CREATE TABLE symbol_daily_ohlc (
 cdate date,
 open numeric(8,2),
 high numeric(8,2),
 low numeric(8,2),
 close numeric(8,2),
 sma8 numeric(8,2)
);
触发功能:

create or replace function update_sma8() RETURNS TRIGGER AS
$$
BEGIN
UPDATE symbol_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 symbol_daily_ohlc sec
)s where s.cdate = NEW.cdate  --The newly inserted cdate
 AND d.cdate = s.cdate;   
RETURN NULL;
END $$ language plpgsql;
表上的触发器设置:

CREATE TRIGGER trig_update_sma
AFTER INSERT ON symbol_daily_ohlc
FOR EACH ROW
EXECUTE PROCEDURE update_sma8();
这对于给定的表(即symbol_daily_ohlc)很有效。我想使用相同的触发器函数,即update_sma8(),用于具有相同模式的任何表(我不想为不同的表重写相同的函数)

我尝试用TG_table_name替换表名(即symbol_daily_ohlc),但没有成功-抛出错误。那怎么做呢


参考资料:

我认为您可能必须使用SQL生成SQL,然后运行生成的SQL。比如:

select CONCAT('create or replace function update_sma8() RETURNS TRIGGER AS
  $$
  BEGIN
  UPDATE ', table_name, '  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 ', table_name, '
  )s where s.cdate = NEW.cdate  --The newly inserted cdate
  AND d.cdate = s.cdate;   
  RETURN NULL;
  END $$ language plpgsql;
') from information_schema.tables
但实际上你应该考虑戈登的建议(和我的后续),把你所有的数据放回一个表:

SELECT CONCAT('INSERT INTO all_hist SELECT ''', table_name, ''', t.* FROM ', table_name) FROM information_schema.tables
这将生成一组SQL,将所有表数据放入all_hist,该表应具有与其他数千个表相同的模式,除了附加列“symbol”或其他任何内容


如果您真的需要,您可以使用类似的技巧创建一组视图来重新创建千表方法。

您可以使用相同的过程来执行并返回所有表的触发器,但不能对所有表使用相同的触发器

下面是一个块,它动态创建一个带有表名后缀的触发器(使用
executeformat

这是您的触发器,它从
TG\u table\u name

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

EXECUTE format ('UPDATE %I 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 %I sec
)s where s.cdate = %L  --The newly inserted cdate
     AND d.cdate = s.cdate',TG_TABLE_NAME,TG_TABLE_NAME,NEW.cdate);   
RETURN NULL;

END $$ language plpgsql;


正如其他人所建议的,使用相同结构的多个表不是一个好主意。您应该考虑将它们合并到一个表中。

不应该使用具有相同模式的表。如果您正在考虑这样一件事,那么您的数据模型可能有问题。所有这些数据都应该放在一个表中,表中的列定义了您希望数据具有的任何其他属性。数据库用于存储股票市场的历史数据,即不同符号(股票)的历史数据。我认为这是研究特定股票的更好方法。然而,如果有一个名为“股票符号”的专栏,就意味着这个问题就不会发生。如果你愿意,你仍然可以拥有一百万张“桌子”<代码>创建查看msft_历史,从所有_股票_历史中选择*,股票_符号='msft';创建查看goog_历史记录作为从所有stock_历史记录中选择*,其中stock_symbol='goog'而不是
更新
将您想要的值分配给
伪记录的各个列。这样,触发器主体中就不会有表名,并且可以将其用于包含您所寻址列的每个表(当然是兼容类型的)。@GordonLinoff我接受了您的建议,并相应地更改了我的数据库。谢谢你和Caius Jard你能回答我真是太好了。非常感谢。我也会评估其他人的建议。谢谢你的回答。我会评估你的建议。
create or replace function update_sma8() RETURNS TRIGGER AS
$$
 BEGIN

EXECUTE format ('UPDATE %I 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 %I sec
)s where s.cdate = %L  --The newly inserted cdate
     AND d.cdate = s.cdate',TG_TABLE_NAME,TG_TABLE_NAME,NEW.cdate);   
RETURN NULL;

END $$ language plpgsql;