创建或替换触发器 postgres

Posted

技术标签:

【中文标题】创建或替换触发器 postgres【英文标题】:Create or replace trigger postgres 【发布时间】:2016-06-25 22:32:49 【问题描述】:

我想为 postgres 表“创建或替换”触发器。但是没有这样的sql表达式。

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

我的问题是:

    是否有比(DROP + CREATE 触发器)推荐/更好的选项 没有这样的“创建或替换触发器”是否有原因(这可能暗示我不应该这样做)

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

    是否为 Postgres 计划过这样的命令?

【问题讨论】:

我来自未来 :D 因为版本 14 有 OR REPLACE 子句用于 CREATE TRIGGER -> postgresql.org/docs/current/sql-createtrigger.html 【参考方案1】:

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

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

【讨论】:

轰隆隆。你真的救了我的命【参考方案2】:

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

This 很好地描述了 postgre 的事务 DDL 与其他系统(例如 oracle)的比较

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

【讨论】:

为什么 postgreql 允许 CREATE OR REPLACE FUNCTION 而不允许 CREATE OR REPLACE TRIGGER... 如果它要遵循一个概念,它应该对函数强制执行它对吗?还是我错了? 现在向我提出百万美元的问题,寻求真相! 我认为其他对象可能依赖于触发器,如果​​您删除触发器,它也会删除其他对象(在级联的情况下)。 这不是真的。由于ERROR: cannot drop view currency_rate because other objects depend on it DETAIL: composite type consume_info column currency_rate depends on type currency_rate,我无法删除视图 @CrystalPaladin 您不能删除正在被另一个函数使用的函数。 DROPCREATE 技术不适用于函数,这就是 CREATE OR REPLACE 存在的原因。【参考方案3】:

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

例子:

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

【讨论】:

BEGIN;COMMIT; 拍在那里,你应该会很好。【参考方案4】:

你可以使用下面的代码。

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 $$;

【讨论】:

【参考方案5】:

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

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;
$$

【讨论】:

【参考方案6】:

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

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

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

在分区表上创建行级触发器将导致在其每个现有分区上创建相同的“克隆”触发器;并且稍后创建或附加的任何分区也将具有相同的触发器。如果子分区上已经存在名称冲突的触发器,则会发生错误,除非使用 CREATE OR REPLACE TRIGGER,在这种情况下,该触发器将替换为克隆触发器。当一个分区与其父分区分离时,它的克隆触发器将被删除。

同样值得注意:

目前,约束触发器不支持 OR REPLACE 选项。

【讨论】:

【参考方案7】:

这是一个 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.triggersql_file.suffix'
  with new_sql_file.open("w", encoding="utf8") as f:
    f.write(new_sql_str)

【讨论】:

以上是关于创建或替换触发器 postgres的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个 Postgres 11 触发器函数,该函数在插入或更新到表“a”时在表“b”中插入一个新行?

Postgres 创建触发器函数以在允许插入之前将值从一列复制到另一列

这个 postgres 触发函数有啥问题?

postgres 触发器创建索引:BEFORE INSERT ON 隐藏一行

在 Postgres 中使用审计表为 NOTIFY/LISTEN 创建触发器是个好主意吗?

Postgres SQL 触发器在 TableB 上插入或更新后使用新值更新 TableA.column