创建或替换触发器 postgres

Create or replace trigger postgres

我想 "create or replace" 一个 postgres table 的触发器。但是,没有这样的sql表达式。

我知道我可以先做一个“DROP TRIGGER IF EXISTS”(http://www.postgresql.org/docs/9.5/static/sql-droptrigger.html)。

我的问题是:

  1. 是否有 recommended/better 选项而不是 (DROP + CREATE 触发器)
  2. 有没有这样的原因"create or replace trigger"(这可能意味着我不应该想要这样做)

注意在oracle中有一个“Create or Replace Trigger”(https://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm)。然后,

  1. 是否为 Postgres 计划了这样的命令?

Postgresql 有事务 DDL,所以 BEGIN > DROP > CREATE > COMMIT 等同于 CREATE OR REPLACE

This 是一篇很好的文章,介绍了 postgre 的事务性 DDL 与其他系统(例如 oracle)的比较

当前 postgres 计划的有关 triggers 的功能不包括添加 REPLACE 语法。

无法创建或替换触发器,但可以这样做

DROP TRIGGER IF EXISTS yourtrigger_name on "yourschemaname"."yourtablename";

您应该使用两个语句:一个用于放置触发器,另一个用于创建触发器。

示例:

DROP TRIGGER IF EXISTS my_trigger
  ON my_schema.my_table;
CREATE TRIGGER my_trigger
  BEFORE INSERT OR UPDATE
  ON my_schema.my_table
  FOR EACH ROW EXECUTE PROCEDURE my_schema.my_function();

您可以使用下面的代码。

DO $$ BEGIN

CREATE (trigger, type , ...);

EXCEPTION
  WHEN others THEN null;
END $$;

示例:

DO $$ BEGIN

CREATE TRIGGER trigger_workIDExist
  BEFORE INSERT OR UPDATE ON "GalleryModel"
  FOR EACH ROW EXECUTE PROCEDURE check_workIDExist();

EXCEPTION
  WHEN others THEN null;
END $$;

您可以在 SQL 中将 CREATE OR REPLACE FUNCTION trigger_function 与以下脚本结合使用:

DO $$
BEGIN
  IF NOT EXISTS(SELECT *
    FROM information_schema.triggers
    WHERE event_object_table = 'table_name'
    AND trigger_name = 'trigger_name'
  )
  THEN
    CREATE TRIGGER trigger_name AFTER INSERT ON table_name FOR EACH ROW EXECUTE PROCEDURE trigger_function();
  END IF;
END;
$$

这是一个 Python 脚本,它从 postgresql 转储文件中提取所有触发器以进行重建。我使用许多与 QGIS 配合得很好的堆叠视图;这对维护依赖视图有很大帮助。

基于 Ali Bagheri 的出色回答。

import pathlib
import re
import sys

re_pat_str = r'^\s*CREATE TRIGGER.*?;\s*$'

sql_wrapper_str = """
DO $$ BEGIN
{trigger_str}
EXCEPTION WHEN others THEN null;
END $$;
"""

if __name__ == "__main__":
  sql_file = pathlib.Path(sys.argv[1])
  with sql_file.open("r", encoding="utf8") as f:
    sql_str = f.read()

  re_pat = re.compile(re_pat_str, re.MULTILINE | re.DOTALL)

  parts = []
  for i, m in enumerate(re_pat.finditer(sql_str)):
    parts.append(sql_wrapper_str.format(trigger_str=m[0].strip()))

  new_sql_str = "\n".join(parts)
  new_sql_file = sql_file.parent / f'{sql_file.stem}.trigger{sql_file.suffix}'
  with new_sql_file.open("w", encoding="utf8") as f:
    f.write(new_sql_str)

从 PostgreSQL 14 开始,CREATE TRIGGER now also supports "OR REPLACE"

您现在可以使用 CREATE OR REPLACE TRIGGER ...(而不是先使用 DROP TRIGGER IF EXISTS)。

这似乎也明智地处理了分区表的情况:

Creating a row-level trigger on a partitioned table will cause an identical “clone” trigger to be created on each of its existing partitions; and any partitions created or attached later will have an identical trigger, too. If there is a conflictingly-named trigger on a child partition already, an error occurs unless CREATE OR REPLACE TRIGGER is used, in which case that trigger is replaced with a clone trigger. When a partition is detached from its parent, its clone triggers are removed.

同样值得一提的是:

Currently, the OR REPLACE option is not supported for constraint triggers.