Sap*_*Sap 6 mysql logging triggers
我正在编写一个触发器来跟踪表中发生的所有更改.不幸的是,这个表有150多列,我想避免在代码中编写每一列(例如new.col1,new.col2 ....),因此我在"更新触发器后"编写了一个以下查询
INSERT INTO logs SELECT *, NOW() FROM abc WHERE abc.id = NEW.Id;
Run Code Online (Sandbox Code Playgroud)
由于更新查询中未更改的数据重复,此想法导致多个问题.
简而言之,我想动态地找出哪些列是更新查询的一部分,如果不可能,有一种方法可以遍历"new"行的所有列,这样我就可以动态地比较旧的.@ colName == new @ COLNAME?
我已经看过 Oracle PL/SQL:动态循环触发列,如何确定t-sql和MySQL UPDATE触发器中更新触发器中是否有任何更改:插入实际更改的列的值.
最后一个链接是关闭到我需要的只有一个区别,我不想在下面的语句中硬编码列名,因为我在所有表中有100多列我将要编写类似的触发器!!
IF NEW.column1 <> OLD.column1 THEN INSERT INTO... END IF; IF NEW.column2 <> OLD.column2 THEN INSERT INTO... END IF
Run Code Online (Sandbox Code Playgroud)
小智 4
今天早上我对此进行了一些研究,看起来我遇到了很多与您相同的搜索结果。最终,在我看来,没有办法循环所有表列并引用相应的旧/新值。我决定明确检查每一列,然后记录:
IF (NEW.fld1 <> OLD.fld1) OR (NEW.fld1 IS NOT NULL AND OLD.fld1 IS NULL) OR (NEW.fld1 IS NULL AND OLD.fld1 IS NOT NULL) THEN
INSERT INTO `fld_audit` (`table`, `fldname`, `oldval`, `newval`)
VALUES ("tblname", "fld1", OLD.fld1, NEW.fld1);
END IF;
IF (NEW.fld2 <> OLD.fld2) OR (NEW.fld2 IS NOT NULL AND OLD.fld2 IS NULL) OR (NEW.fld2 IS NULL AND OLD.fld2 IS NOT NULL) THEN
INSERT INTO `fld_audit` (`table`, `fldname`, `oldval`, `newval`)
VALUES ("tblname", "fld2", OLD.fld2, NEW.fld2);
END IF; ...
Run Code Online (Sandbox Code Playgroud)
我在这里找到了另一种解决方案的线索。理论上,您可以有 3 个分隔列表,一个用于列名,一个用于旧值,一个用于新值。您必须显式引用旧的和新的值,但这将是一行(更容易维护或复制/粘贴以在其他表上实现),然后您可以循环。所以在伪代码中它看起来像这样:
fields_array = concat_ws(",", "fld1", "fld2");
old_vals_array = concat_ws(",", OLD.fld1, OLD.fld2);
new_vals_array = concat_ws(",", NEW.fld1, NEW.fld2);
foreach fields_array as key => field_name
INSERT INTO `fld_audit` (`table`, `fldname`, `oldval`, `newval`)
VALUES ("tblname", field_name, old_vals_array[key], vew_vals_array[key]);
Run Code Online (Sandbox Code Playgroud)
我还没有想太多。您可能需要调用存储过程而不是设置变量。但这可能值得研究一下。我已经在触发器上花了足够的时间了。不确定我是否可以(向我的老板)验证更优雅的解决方案的试错时间。