postgresql如何在没有任何更改的情况下停止触发器添加行

postgresql如何在没有任何更改的情况下停止触发器添加行,postgresql,Postgresql,我想将对我的工作表的更改记录到我的历史表中,但仅当值在更新过程中发生更改时,我尝试创建更新历史触发器,但无论值是否已更改,它都会添加一行,例如,假设我的工作表中有以下内容: shift_id|site |organisational_unit --------|---------|------------------- 123475|site01 |my org 如果我执行更新查询 UPDATE working SET site = $1, orga

我想将对我的
工作
表的更改记录到我的
历史
表中,但仅当值在更新过程中发生更改时,我尝试创建更新历史触发器,但无论值是否已更改,它都会添加一行,例如,假设我的工作表中有以下内容:

shift_id|site     |organisational_unit
--------|---------|-------------------
  123475|site01   |my org              
如果我执行更新查询

UPDATE working SET site = $1, organisational_unit = $2 WHERE shift_id=$3', ['site01', 'my new org', '123475']
这在历史记录表1中为
站点创建了一行
,即使它没有改变值,我也只想为组织单位的改变创建一行

historyid|shiftid|fieldname          |oldvalue |newvalue   |updatedat          |
---------|-------|-------------------|---------|-----------|-------------------|
        7| 123475|organisational_unit|my org   |my new org |2019-07-01 10:21:19|
        8| 123475|site               |site01   |site01     |2019-07-01 10:21:19|

我的扳机是这样的

-- create function for updates to track history
CREATE function update_history ()
RETURNS TRIGGER
as $$
BEGIN
    -- check if data in column has changed between the update
    IF NEW.client_id <> OLD.client_id THEN

        -- if it has insert a row to the history table detailing the changes
        INSERT INTO history (ShiftId, fieldName, OldValue, NewValue)
        VALUES(New.shift_id, 'client id ', OLD.client_id, NEW.client_id);

    -- if nothing has changed don't do anything
    END IF;

    IF NEW.organisational_unit <> OLD.organisational_unit THEN
        INSERT INTO history (ShiftId, fieldName, OldValue, NewValue)
        VALUES(New.shift_id, 'organisational_unit', OLD.organisational_unit, NEW.organisational_unit);
    END IF;

    IF NEW.site <> OLD.site THEN
    INSERT INTO history
        (ShiftId, fieldName, OldValue, NewValue)
    VALUES(New.shift_id, 'site', OLD.site, NEW.site);
    END IF;

return null;
END;
$$
language plpgsql;
--为跟踪历史记录的更新创建函数
创建函数更新\u历史记录()
返回触发器
作为$$
开始
--检查列中的数据在更新之间是否已更改
如果NEW.client\u id为OLD.client\u id,则
--如果有,则在历史记录表中插入一行,详细说明更改
插入历史记录(ShiftId、fieldName、OldValue、NewValue)
值(New.shift\u id、'client id',OLD.client\u id,New.client\u id);
--如果什么都没有改变,就什么都不要做
如果结束;
如果是新的。组织单位旧的。组织单位
插入历史记录(ShiftId、fieldName、OldValue、NewValue)
价值观(新的轮班id,“组织单位”,旧的组织单位,新的组织单位);
如果结束;
如果是NEW.site OLD.site,则
载入历史
(ShiftId、字段名、OldValue、NewValue)
值(New.shift_id,'site',OLD.site,New.site);
如果结束;
返回null;
结束;
$$
语言plpgsql;

要检查列是否已更改,请不要使用
。它不考虑空值。使用

IF NEW.client_id IS DISTINCT FROM OLD.client_id
...
如果新的与旧的不同,则使用
检查整行

如果要防止插入到主表中,它应该是更新之前的
触发器,并且应该执行

返回null


只有在不需要插入的情况下,最有效的方法是定义仅在某些列更改时触发的触发器:

CREATE TRIGGER ... BEFORE UPDATE ON ... FOR EACH ROW
   WHEN (NEW IS DISTINCT FROM OLD)
   EXECUTE FUNCTION update_history();

这避免了在不必要的情况下执行该函数。

或检查整行:
如果新的与旧的不同
另外:OP可以将条件移动到触发器(他没有显示),这正是我想要的:)对我有效: