这里我有一个工作的MySQL触发器:
DROP TRIGGER IF EXISTS trg_after_update_tbl1;
DELIMITER //
CREATE TRIGGER trg_after_update_tbl1
AFTER UPDATE ON db1.tbl1 FOR EACH ROW
BEGIN
DECLARE strOld VARCHAR(255);
DECLARE strNew VARCHAR(255);
SET strOld = '';
SET strNew = '';
IF (NEW.colA <> OLD.colA) THEN
SET strOld = CONCAT(strOld, 'colA: ',OLD.colA,'; ');
SET strNew = CONCAT(strNew, 'colA: ',NEW.colA,'; ');
END IF;
IF (NEW.colB <> OLD.colB) THEN
SET strOld = CONCAT(strOld, 'colB: ',OLD.colB,'; ');
SET strNew = CONCAT(strNew, 'colB: ',NEW.colB,'; ');
END IF;
IF (NEW.colC <> OLD.colC) THEN
SET strOld = CONCAT(strOld, 'colC: ',OLD.colC,'; ');
SET strNew = CONCAT(strNew, 'colC: ',NEW.colC,'; ');
END IF;
-- AND SO MANY COLUMN CLAUSES ON....
INSERT INTO db1.changes (user, tableName, oldData, newData, date)
VALUES (
user(),
'tableA',
strOld,
strNew,
now()
);
END//
DELIMITER ;
是否有可能从列表,数组或类似的东西将表列名分配给变量(例如X),迭代它并使用一个IF子句?像这样(伪代码):
BEGIN LOOP
IF (NEW.X <> OLD.X) THEN
SET strOld = CONCAT(strOld, X, ': ',OLD.X,'; ');
SET strNew = CONCAT(strNew, X, ': ',NEW.X,'; ');
END IF;
END LOOP
无论使用哪种DBMS,您所建议的通常被称为动态SQL,这意味着您正在执行的语句首先需要编译然后执行。
虽然您可以减少代码行数,但您也将影响(负面)性能。
就像我常说的,你写了一次代码,但是你读了很多遍,甚至运行了很多次。寓意:在需要的时候,花一些额外的努力使你的代码可读性和效率。
在任何情况下,MySQL提供了准备好的语句,这是它的动态SQL版本。
我上面写的有一个例外:当您的两个表包含一定数量的列时,所有列都是相同的类型。在这种情况下,您可以选择两个记录的内容到两个数组中,然后循环遍历数组(这只是最后一刻的想法)。