用触发器函数替换删除:如何 return 影响行数?

Replace delete with trigger function: how to return affected row count?

标准delete from foo_history where id = 123;return正文:

DELETE 1

我创建了一个触发器过程来替换删除触发器,而不是删除,设置一个存档标志:

CREATE FUNCTION archive()
  RETURNS trigger AS $$
    DECLARE
      command text := '" SET timeEnd = current_timestamp WHERE id = ';
    BEGIN
      EXECUTE 'UPDATE "' || TG_TABLE_NAME || command USING OLD.id;
      RETURN NULL;
    END;
  $$ LANGUAGE plpgsql;

然后为 foo_history table 创建了一个名为 foo:

的视图
CREATE VIEW foo AS
SELECT id, timeStart from foo_history WHERE timeEnd IS NULL;

并向视图添加触发器:

CREATE TRIGGER foo_archive INSTEAD OF DELETE ON foo FOR EACH ROW EXECUTE PROCEDURE archive();

换句话说,当删除 foo 记录时,改为设置 timeEnd 列 - 这样,foo 视图仅显示未设置 timeEnd 的记录。

这个效果很好:

delete from foo where id = 123

确实设置了 timeEnd 列。但是,此输出是:

DELETE 0

而我真的很想说:

DELETE 1

作为一名 SQL 新手和 Postgres 新手,我不确定如何更改存档功能来执行此操作。

我确实尝试将其更改为:

RETURN 1

但是我得到一个错误,关于我需要 return 一个复合材料(无论那意味着什么)。

当然,第二个我 post 这个,我有一个似乎可行的想法..

而不是RETURN NULL,使用RETURN OLD

对不起...

您已经发现您需要 RETURN OLDINSTEAD OF 触发器中进行 DELETE 操作以使行 count 在返回的 命令标记 中。手册:

A row-level INSTEAD OF trigger should either return NULL to indicate that it did not modify any data from the view's underlying base tables, or it should return the view row that was passed in (the NEW row for INSERT and UPDATE operations, or the OLD row for DELETE operations). A nonnull return value is used to signal that the trigger performed the necessary data modifications in the view. This will cause the count of the number of rows affected by the command to be incremented.

大胆强调我的。

但是您的当前触发器中也有一个偷偷摸摸的 SQL 注入错误TG_TABLE_NAME 是没有引号的裸名。标识符必须被视为用户输入 - 并且在任何情况下都必须根据需要引用。在动态 SQL 语句中正确引用 table 名称(否则您可能会遭受后果)。一种方法是使用 format():

CREATE OR REPLACE FUNCTION archive()
  RETURNS trigger AS
$func$
BEGIN
   EXECUTE format('UPDATE %I SET time_end = current_timestamp WHERE id = ', TG_TABLE_NAME)
   USING OLD.id;
   RETURN OLD;
END
$func$  LANGUAGE plpgsql;

相关:

我还使用 time_end 而不是 timeEnd,因为我的长期建议是避免在 Postgres 中使用 CaMeL 大小写标识符。相关:

  • Are PostgreSQL column names case-sensitive?