小编典典

更新特定列后的PostgreSQL触发器

sql

我正在探索触发器,并希望创建一个在game_saved列上的Update事件后触发的触发器。正如我在PostgreSQL文档中所读到的那样,可以为列创建触发器。该列包含boolean值,因此用户可以将游戏添加到他的收藏中或将其删除。因此,我希望触发器函数能够game_saved为特定用户计算在该列中设置为TRUE的游戏数量。然后total_game_count在一个game_collection表中更新。

game_collection

id - BIGSERIAL primary key
user_id - INTEGER REFERENCES users(id)
total_game_count - INTEGER

game_info

id - BIGSERIAL primary key
user_id - INTEGER REFERENCES users(id)
game_id - INTEGER REFERENCES games(id)
review - TEXT
game_saved - BOOLEAN

这是我的触发器(它不起作用,我想找出原因):

CREATE OR REPLACE FUNCTION total_games() 
RETURNS TRIGGER AS $$ 
BEGIN 
UPDATE game_collection 
SET total_game_count = (SELECT COUNT(CASE WHEN game_saved THEN 1 END)
                        FROM game_info WHERE game_collection.user_id = game_info.user_id)
WHERE user_id = NEW.user_id; 
RETURN NEW; 
END; 
$$ LANGUAGE plpgsql;

CREATE TRIGGER tr_total_games 
AFTER UPDATE OF game_saved FOR EACH ROW 
EXECUTE PROCEDURE total_games();

如果我将AFTER UPDATE OF game_saved(列)更改为AFTER UPDATE ON game_info(表),则触发器可以正常工作。因此,专门为列更新创建触发器存在一些问题。

在列更新上触发触发器是一个好主意,还是我应该在这里寻找另一种方法?


阅读 193

收藏
2021-04-22

共1个答案

小编典典

语法为:

CREATE TRIGGER tr_total_games 
AFTER **UPDATE OF game_saved ON game_info**
FOR EACH ROW 
EXECUTE PROCEDURE total_games();

(如手册中所记录。)

但是整个方法是可疑的。在并发写入负载下,通过触发器使聚合保持最新状态很容易出错。

没有并发写入负载,有更简单的解决方案:只需从当前总数中加/减1 …

可靠的解决方案是 VIEW
game_collection.total_game_count完全删除该列,也可能删除整个表game_collection,这似乎没有任何其他用途。

CREATE VIEW v_game_collection AS
SELECT user_id, count(*) AS total_game_count
FROM   game_info
WHERE  game_saved
GROUP  BY user_id;

这将返回在game_info其中至少有1行的所有用户game_saved IS TRUE(并忽略所有其他用户)。

对于非常大的表,您可能需要MATERIALIZED VIEW或相关的解决方案来提高读取性能。

2021-04-22