创建或替换触发器 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 您不能删除正在被另一个函数使用的函数。 DROP
和 CREATE
技术不适用于函数,这就是 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 触发器创建索引:BEFORE INSERT ON 隐藏一行