2017-04-23 87 views
1

我正在探索触发器,并且想要创建一个在game_saved列的Update事件之后触发的触发器。正如我在PostgreSQL docs中读到的,可以为列创建触发器。该列包含boolean值,因此用户可以将游戏添加到他的收藏或删除它。所以我想要触发函数来计算某个用户在game_saved列中设置为TRUE的游戏数量。然后在game_collection表中更新total_game_countPostgreSQL在更新特定列后触发

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(表),则触发器将正常工作。所以在创建专门用于列更新的触发器时存在一些问题。

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

+0

你引用手册版本9.4的任何原因?你的Postgres版本是什么? –

回答

1

的语法是:

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; 

这将返回所有用户都至少有1列game_info其中game_saved IS TRUE(和忽略所有其他)。

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

+1

谢谢你的出色答案。它帮助我理解了一种更好的方法,了解Views并将它们合并到我的项目中。 – samba