我正在探索触发器,并希望创建一个在game_saved列上的Update事件后触发的触发器。正如我在PostgreSQL文档中所读到的那样,可以为列创建触发器。该列包含boolean值,因此用户可以将游戏添加到他的收藏中或将其删除。因此,我希望触发器函数能够game_saved为特定用户计算在该列中设置为TRUE的游戏数量。然后total_game_count在一个game_collection表中更新。
game_saved
boolean
total_game_count
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(表),则触发器可以正常工作。因此,专门为列更新创建触发器存在一些问题。
AFTER UPDATE OF game_saved
AFTER UPDATE ON game_info
在列更新上触发触发器是一个好主意,还是我应该在这里寻找另一种方法?
语法为:
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,这似乎没有任何其他用途。
VIEW
game_collection.total_game_count
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(并忽略所有其他用户)。
game_saved IS TRUE
对于非常大的表,您可能需要MATERIALIZED VIEW或相关的解决方案来提高读取性能。
MATERIALIZED VIEW