【问题标题】:Create trigger to automatically update column with subquery创建触发器以使用子查询自动更新列
【发布时间】:2021-09-26 17:28:43
【问题描述】:

在我的应用程序中,我有几个表,lessonsvotes。它们的外观如下:

课程

+-------------+---------+----------------------+
| Column      | Type    | Modifiers            |
|-------------+---------+----------------------|
| id          | uuid    |  not null            |
| votes_total | integer |  not null default 0  |
+-------------+---------+----------------------+

投票

+-------------+---------+-------------+
| Column      | Type    | Modifiers   |
|-------------+---------+-------------|
| positive    | boolean |  not null   |
| user_id     | uuid    |  not null   |
| lesson_id   | uuid    |  not null   |
+-------------+---------+-------------+

每当votes 中的一行被插入、更新或删除时,我想使用子查询更新相关课程的votes_total 列。这是我尝试过的:

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();

但是,当我尝试在迁移中运行它时,我收到以下错误:

(Postgrex.Error) ERROR 42601 (syntax_error) cannot insert multiple commands into a prepared statement

【问题讨论】:

    标签: sql postgresql triggers


    【解决方案1】:

    您好,您的函数必须返回一个触发器。您不能在删除触发器中使用 new。您必须创建至少 2 个调用相同函数的触发器,并使用TG_OP 知道该函数是由插入、更新还是删除触发的。

    然后在 case 或 if 语句中,您可以使用 new 或 old 来获取 id 的值。

    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();
    

    【讨论】:

    • 感谢您的帮助!函数语法现在似乎是正确的,我可以独立创建它。但是,在尝试运行代码的触发器部分时,我仍然收到 cannot insert multiple commands into a prepared statement 错误。
    • 你从哪里得到错误?在 PGAdmin 中,在您软件的代码中?
    • 啊,我明白了。我在我的迁移系统中得到了这个,因为 SQL 字符串中有多个语句。触发器函数没有任何问题——它只是导致错误的第二条语句。谢谢大家的帮助!
    猜你喜欢
    • 2015-07-25
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 2020-09-29
    • 2011-03-10
    • 1970-01-01
    相关资源
    最近更新 更多