有没有办法在MySQL触发器中动态引用NEW/OLD值?

zi8p0yeb  于 2023-11-16  发布在  Mysql
关注(0)|答案(1)|浏览(138)

我试图在数据库触发器中实现行的版本控制。我有2个表:
1.地址(ID,城市,街道,国家)

  1. address_versions(id,object_changes)
    我想在addresses_versions表中创建一行,每次从地址表中更改一行。
    我创建了以下触发器:
CREATE TRIGGER `addresses_after_create` AFTER INSERT ON `addresses` FOR EACH ROW
    this_trigger:BEGIN
    DECLARE object_changes_json JSON;

    -- Prepare object_changes JSON for address_versions row creation
    SET object_changes_json = JSON_OBJECT();

    IF COALESCE(OLD.city, '') <> COALESCE(NEW.city, '') THEN
        SET object_changes_json = JSON_SET(object_changes_json, '$.city', JSON_ARRAY(OLD.city, NEW.city));
    END IF;

    IF COALESCE(OLD.street, '') <> COALESCE(NEW.street, '') THEN
        SET object_changes_json = JSON_SET(object_changes_json, '$.street', JSON_ARRAY(OLD.street, NEW.street));
    END IF;

    IF COALESCE(OLD.country, '') <> COALESCE(NEW.country, '') THEN
        SET object_changes_json = JSON_SET(object_changes_json, '$.country', JSON_ARRAY(OLD.country, NEW.country));
    END IF;

    INSERT INTO address_versions (object_changes)
    VALUES (object_changes_json);

字符串
因此,每次我更改地址表中的一行时,都会使用更改值的JSON创建address_versions行。
但是上面的解决方案的问题是,我每次向表中添加/删除列时都需要更新触发器。
有没有一种方法可以让它更动态?
我试图创建一个单独的表与列名和循环通过它,但我不能访问新/旧值动态

...
    read_loop: LOOP
        FETCH cursor_column_name INTO column_name_string;
        IF done THEN
            LEAVE read_loop;
        END IF;
        IF COALESCE(OLD.column_name_string, '') <> COALESCE(NEW.column_name_string, '') THEN
            SET object_changes_json = JSON_SET(object_changes_json, '$.additional_info', JSON_ARRAY(OLD.column_name_string, NEW.column_name_string));
        END IF;
    END LOOP;
...


但它失败了:

=> ERROR 1054 (42S22): Unknown column 'column_name_string' in 'OLD'


是否有方法动态引用新/旧值?

ia2d9nvy

ia2d9nvy1#

不可以。游标返回的是数据值(字符串/数字/日期等),而不是标识符。如果不使用动态SQL,就不能将字符串用作标识符。
但是在触发器中,不允许使用动态SQL。
因此,您需要在添加或删除列的同时部署更新的触发器。
我承认这是很难做到没有停机时间。
另一种方法是在更新addresses表之后使用应用程序代码更新address_versions

相关问题