更新特定列后的PostgreSQL触发器

时间:2017-04-23 10:36:34

标签: sql postgresql database-design triggers

我正在探索触发器的方式,并希望创建一个在boolean列上的Update事件后触发的触发器。正如我在PostgreSQL docs中读到的那样,可以为列创建触发器。该列包含game_saved值,因此用户可以将游戏添加到其集合中或将其删除。所以我希望触发器功能计算某个用户在total_game_count列中设置为TRUE的游戏数量。然后在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(列)更改为{{1}}(表格),则触发器可以正常工作。因此,专门为列更新创建触发器存在一些问题。

在列更新时触发触发器是一个好主意还是我应该在这里寻找其他方法?

1 个答案:

答案 0 :(得分:4)

语法为:

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

(As documented in the manual.)

但整个方法都是可疑的。通过触发器保持聚合更新在并发写入负载下容易出错。

没有并发写入加载,有更简单的解决方案:只需从当前总计中加/减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_infogame_saved IS TRUE至少有1行的所有用户(并忽略所有其他行)。

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