我有一组表,它们使用一个鉴别器列来区分实体类型。这些表中的某些表描述了已定义的实体组之间的关系,或者包含特定类型实体的更多信息。我想对表中的数据进行完整性检查。最初这些是作为支票编写的,但postgres不能很好地处理备份中的表排序,所以我想把检查重写为触发器,这样我就可以在恢复数据库时关闭触发器。
由于实体的实际列名将从表更改为表,并且我想以DRY方式执行,我尝试编写单个触发器函数,该实体将实体的id作为参数并验证它是正确的类型。
我正在尝试调用带参数的函数触发器
c.is_earth_based_measurement_tg(bigint).
实际触发器编写如下:
CREATE TRIGGER earth_based_measurement_locations_tg1
BEFORE INSERT OR UPDATE
ON measurements.earth_based_measurement_locations
FOR EACH ROW
EXECUTE PROCEDURE c.is_earth_based_measurement_tg(NEW.fk_measurement);
当我尝试保存触发器时,我得到'错误:语法错误在或接近“。”'指的是NEW.fk_measurement。编写此触发器的正确方法是什么?
感谢。
答案 0 :(得分:5)
您不需要传递NEW.anything
作为参数;它会自动作为变量NEW
提供给触发器函数。因此,只要NEW.fk_measurement
为tg_op
或INSERT
(UPDATE
未设置为NEW
,您的触发器就可以从其中的任何位置访问DELETE
}或TRUNCATE
触发器。)
触发器可以带参数,但它们在TG_ARGV
中出现(为零323个音符)。它们不需要用于列值,实际上不能引用列值;它们的目的是用于参数化触发器,具有可选功能的触发器等等。
在重新阅读您的问题时,您需要一个感兴趣的列名参数。不幸的是,在NEW
元组中通过动态名称访问列非常尴尬。
您可以将触发器创建为:
CREATE TRIGGER earth_based_measurement_locations_tg1
BEFORE INSERT OR UPDATE
ON measurements.earth_based_measurement_locations
FOR EACH ROW
EXECUTE PROCEDURE c.is_earth_based_measurement_tg('fk_measurement');
即。将colname作为字符串文字传递。
触发程序将定义为:
CREATE OR REPLACE FUNCTION is_earth_based_measurement_tg() RETURNS trigger AS $$
BEGIN
IF tg_op = 'INSERT' OR tg_op = 'UPDATE' THEN
PERFORM my_func(hstore(NEW) -> TG_ARGV[0]);
END IF;
END;
$$ LANGUAGE plpgsql;
...或者您要对从列中提取的值进行的任何其他操作。
你无法通过当前PostgreSQL版本中的动态列名设置NEW
中列的值(直到并包括9.4)。
请注意,我们将NEW
元组转换为hstore,然后按列名取消引用它。
答案 1 :(得分:1)
不能使用参数声明触发器函数。 OLD
,NEW
和几个触发器相关变量默认使用所谓的TG_ARGV
传递,并且可以在触发器函数内访问,无需额外的步骤。您可以查看official documentation以获取详细信息,但通常看起来应与此类似:
CREATE OR REPLACE FUNCTION is_earth_based_measurement_tg()
RETURNS TRIGGER AS $earth_based_measurement_locations_tg1$
BEGIN
IF (NEW.fk_measurement = 'foo') THEN
-- Do something
END IF;
END;
$earth_based_measurement_locations_tg1$ LANGUAGE plpgsql;