In my application, I have a couple of tables, lessons
and votes
. Here’s what they look like:
Lessons
x
+-------------+---------+----------------------+
| Column | Type | Modifiers |
|-------------+---------+----------------------|
| id | uuid | not null |
| votes_total | integer | not null default 0 |
+-------------+---------+----------------------+
Votes
+-------------+---------+-------------+
| Column | Type | Modifiers |
|-------------+---------+-------------|
| positive | boolean | not null |
| user_id | uuid | not null |
| lesson_id | uuid | not null |
+-------------+---------+-------------+
Whenever a row in votes
is inserted, updated or deleted, I’d like to update the votes_total
column of the related lesson using a subquery. Here’s what I’ve tried:
CREATE PROCEDURE update_lesson_votes_total()
LANGUAGE SQL
AS $$
UPDATE lessons
SET votes_total = (
SELECT SUM(CASE WHEN positive THEN 1 ELSE -1 END)
FROM votes
WHERE lesson_id = NEW.lesson_id
)
WHERE id = NEW.lesson_id;
$$;
CREATE TRIGGER votes_change
AFTER INSERT OR UPDATE OR DELETE ON votes
FOR EACH ROW
EXECUTE PROCEDURE update_lesson_votes_total();
However, when I try to run this in a migration, I get the following error:
(Postgrex.Error) ERROR 42601 (syntax_error) cannot insert multiple commands into a prepared statement
Advertisement
Answer
Hi your function must return a trigger. You can’t use new in a trigger on delete. You have to create at least 2 triggers calling the same function and use TG_OP
to know if the function is triggered by insert, update or delete.
Then in a case or if statement you can use new or old to get the id’s value.
CREATE FUNCTION update_lesson_votes_total()
returns trigger
LANGUAGE plpgsql
AS $$
begin
UPDATE lessons
SET votes_total = (
SELECT SUM(CASE WHEN positive THEN 1 ELSE -1 END)
FROM votes
WHERE lesson_id = NEW.lesson_id
)
WHERE id = NEW.lesson_id;
return null;
end;
$$;
CREATE TRIGGER votes_change_u_i
AFTER INSERT OR UPDATE ON votes
FOR EACH ROW
EXECUTE PROCEDURE update_lesson_votes_total();
CREATE TRIGGER votes_change_d
AFTER DELETE ON votes
FOR EACH ROW
EXECUTE PROCEDURE update_lesson_votes_total();