PostgreSQL触发器在插入/删除数组元素时更新游戏计数

时间:2017-04-22 21:44:40

标签: sql postgresql triggers

我想在game_catalog表上创建一个触发器,这样每次用户从他的收藏中添加或删除游戏时,总游戏数就会更新。由于游戏集合存储为文本数组,我决定使用array_length函数来计算游戏数量。

game_catalog

id - BIGSERIAL primary key
user_id - INTEGER
game_list - text []
game_count - INTEGER

我试图创建一个触发器,以便在插入或删除后重新计算game_list列的长度,但它不起作用。这就是我现在所拥有的:

CREATE OR REPLACE FUNCTION count_games() 
RETURNS TRIGGER AS $$ 
BEGIN 
UPDATE game_catalog 
SET game_count = (SELECT array_length(game_list, 1) from game_catalog) 
WHERE user_id = NEW.user_id; 
RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER count_games 
AFTER INSERT OR DELETE ON game_catalog FOR EACH ROW 
EXECUTE PROCEDURE count_games(); 

1 个答案:

答案 0 :(得分:1)

所以,有几件事:

  • 我不知道你确切的用例,但出于某些原因这似乎是一个坏主意
  • 请确保您对user_id有一个独特的约束,否则这将会变得混乱(您可以在user_id上键入更新。如果要打算键入任何内容,最好使用主键,但事实并非如此必要的,如图所示)[编辑 - 没关系。您的查询已处理此问题。但你确实更新了该用户的每条记录......如果有重复,这可能会变得昂贵......]
  • 如果你真的希望这个项目在没有计算的情况下可供用户使用(因为它总是引用相同的行),它看起来像它真的属于视图或物化视图
  • 通常,当预期有大量数据(即不是通过记录)时,触发器聚合用于表级聚合,并且将存在于单独的表中。当它在同一个表上时,您将面临无限循环的风险(更新行,触发更新,触发更新等)。
  • 一般来说,在关系数据建模中使用数组或json列之前,您应该先问自己很多问题。尽管可能,你可能会为未来的自我创造痛苦
  • 对于DELETE触发器,NEW是未定义的(请参阅有关触发器函数的Postgres文档,它们非常有用且有一些很好的示例)
  • 如果你自己编辑记录本身(效率更高,因为你没有选择查询),你需要使用BEFORE触发器,因为AFTER触发器不能改变进入表格的东西的值

也就是说,您可以不同地定义触发器以使其工作:

-- only watch for insert/updates on the game_list column to avoid infinite loop
-- delete doesn't matter here
CREATE TRIGGER count_games
 BEFORE INSERT OR UPDATE OF game_list
 ON game_catalog
 FOR EACH ROW
 EXECUTE PROCEDURE count_games();

虽然视图会更好:

CREATE OR REPLACE VIEW game_catalog_count AS
SELECT id, user_id, game_list, array_length(game_list,1) as game_count
FROM game_catalog;

你的触发器功能可以使用一点改进(除非你计划引用其他行......但是你的触发器功能设计中还有其他问题):

CREATE OR REPLACE FUNCTION count_games() 
RETURNS TRIGGER AS $$ 
BEGIN 

NEW.game_count := array_length(NEW.game_list, 1);

RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

希望有帮助!