SQL触发器动态访问行的字段

时间:2017-03-28 02:55:01

标签: mysql triggers

目前正在尝试使用通用活动日志表来存储哪些表,字段,值已更改(+必需的主键)

DELIMITER $$
CREATE TRIGGER tr_customers_insert_activity_log AFTER INSERT ON `customers`
    FOR EACH ROW
    BEGIN

      DECLARE curr_column CHAR(255);
      DECLARE finished INT DEFAULT false;
      DECLARE column_name_cursor CURSOR FOR SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'customers' ORDER BY ordinal_position;
      DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET finished = 1;

      OPEN column_name_cursor;
        column_loop: LOOP
          IF finished THEN
            LEAVE column_loop;
          END IF;
          FETCH column_name_cursor INTO curr_column;
          INSERT INTO activity_log(`cid`, `table`, `field`, `value`, `modified_by`, `modified_at`) 
            VALUES (NEW.cid, 'customers', curr_column, NEW.@curr_column, NEW.modified_by, NEW.modified_at);

        END LOOP column_loop;
      CLOSE column_name_cursor;
    END$$
DELIMITER ;

我遇到的问题是:

INSERT INTO activity_log(`cid`, `table`, `field`, `value`, `modified_by`, `modified_at`) 
            VALUES (NEW.cid, 'customers', curr_column, NEW.@curr_column, NEW.modified_by, NEW.modified_at);

由于我按名称动态循环遍历每个字段,因此我不知道如何获得NEW。@ curr_column值。如何使用变量的值访问NEW / OLD对象的属性?

澄清语法错误是:

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@curr_column, NEW.modified_by, NEW.modified_at); END LOOP column_loop' at line 17

谢谢!

1 个答案:

答案 0 :(得分:0)

无法动态解决TRIGGER中的NEW和OLD值。

我们可以使用CASE表达式。但这可能不是你想要的。它不是真的"动态"。我们需要静态地处理我们感兴趣的每个列名称。

  CASE curr_column 
  WHEN 'cid'       THEN NEW.cid
  WHEN 'foo'       THEN NEW.foo
  WHEN 'othercol'  THEN NEW.othercol
  END  

同样有问题的是您可能希望在activity_logvalue列中存储的列的各种数据类型... DATE,INTEGER,DECIMAL,ENUM,VARCHAR,...这些都在进行中需要转换为value列的单个数据类型。

需要考虑的其他选择:

  • 让触发器保存整行的副本

  • 而不是触发" dynamic",使触发器的创建更加动态...即使用来自information_schema.columns的SELECT来帮助生成触发器定义中所需的内容