【问题标题】:MySql AFTER UPDATE trigger with field names带有字段名称的 MySql AF​​TER UPDATE 触发器
【发布时间】:2025-11-29 04:05:02
【问题描述】:

我在下面列出了两个表。当在“switches”上更新字段时,我需要在“switch_updates”中插入一个条目,其中包括更新的字段名称、旧值和新值。

我已包含已启动的触发器,但无法弄清楚如何提取已更新字段的名称。

---------------------
|  switches         |
---------------------
|  id               |
|  name (varchar)   |
|  functional (int) |
---------------------


-----------------------------
|  switch_updates           |
-----------------------------
|  id                       |
|  field_name (varchar)     |
|  field_original (varchar) |
|  field_new (varchar)      |
-----------------------------

触发器

CREATE TRIGGER SwitchUpdate_Trigger
AFTER UPDATE ON switches
FOR EACH ROW
BEGIN
    INSERT into switch_updates (id, switch_id, field_name, field_original, field_new)
    VALUES 
        (
            null,
            NEW.id, -- switch_id
                  , -- field_name?
            OLD.field_value, --?
            NEW.field_value, --?
        );
END;

【问题讨论】:

    标签: mysql triggers


    【解决方案1】:

    你无法直接找到更新的字段名。

    您可以获得的是行(字段)具有的值,以及行(字段)将具有的值(OLDNEW)。
    您可以(手动)将所有字段的旧值与新值进行比较,如果更改,则应将其插入表中。

    可能的问题:

    • 您无法确定某个字段是否不在查询中,或者是否“更新”了相同的值。在这两种情况下,OLDNEW 的值都是相同的
    • 有点费力

    但最终你能像这样得到你想要的吗?

    【讨论】:

      【解决方案2】:

      来自create trigger documentation

      您可以使用别名 OLD 和 NEW 来引用主题表(与触发器关联的表)中的列。 OLD.col_name 指的是现有行更新或删除之前的列。 NEW.col_name 指的是要插入的新行的列或更新后的现有行

      来自一个有趣的blog

      在 INSERT 触发器中,只能使用 NEW.col_name,因为没有旧行。在 DELETE 触发器中,只能使用 OLD.col_name,因为没有新行。在 UPDATE 触发器中,您可以使用 OLD.col_name 引用更新前的行列,使用 NEW.col_name 引用更新后的行列。

      这意味着你应该能够完成你的任务。

      【讨论】:

      • 我不知道这是否属实:它肯定不会从您引用的文本中得出。这只是说明OLDNEW 所指的内容。据我所知,唯一的限制是INSERT 触发器没有OLD,这是微不足道的,因为在插入之前没有数据。
      • @Nanne,我用粗体表示了我的陈述。
      • 还是不正确?即使在更新发生之后,它仍然会在更新之前引用现有的列?同样,您可以在更新行后使用OLD
      • 我也在从事类似的任务。如果您可以获取更改了哪一列而不是为所有列名编写 IF-ELSE,那就太好了。或者,获取所有列名并遍历它们。这可能吗?
      【解决方案3】:

      我实际上在做同样的任务,据我所知,获取更新字段名称的唯一方法是像@Nanne 所说的那样手动检查每个字段。

      基本示例:

      IF OLD.name <> NEW.name THEN
          INSERT INTO audit_table (`field`, `old_value`, `new_value`)
          VALUES ('name', OLD.name, NEW.name);
      END IF;
      

      对要跟踪的列数重复。如果有人知道更好的方法,我很想听听!

      【讨论】:

      • 你找到更好的方法了吗? (我正在解决类似的问题)
      • @LymanZerga,遗憾的是没有......为了减少重复,我以编程方式生成触发器,但实际上这只是给猪穿上衣服:(