Mysql触发器 - 捕获每个列的更改

时间:2014-07-05 08:09:59

标签: mysql sql triggers

我正在尝试创建触发器,在更新后捕获数据库中的更改。

my_table 我正在观看:

enter image description here

my_table_log 我正在编写更改以记录它们 enter image description here

到目前为止这是触发器:

CREATE TRIGGER `log_update` 
AFTER UPDATE ON `my_table` 
FOR EACH ROW 
BEGIN
INSERT INTO 
`my_table_log` 
(
    `id`, 
    `action`, 
    `column_name`, 
    `value_before`, 
    `value_after`, 
    `who`, 
    `ts`
)
VALUES
(
    NEW.id,
    'u', 
    'name',
    OLD.name, 
    NEW.name,
    user(),
    NOW()
);
END

问题:如何记录每个列的更改?

问题:只有在name中列my_table发生变化时,我才会注意到。我为列age设置了另一个触发器。如何为每行和每个已更改的列设置触发器?

感谢您的建议/代码/灵感

2 个答案:

答案 0 :(得分:1)

您可以在触发器中观看的每个列中使用ifs:

create trigger `log_update` 
after update on `my_table` 
for each row
begin

if (old.name <> new.name) then
    insert into `my_table_log`
    (
        `id`, 
        `action`, 
        `column_name`, 
        `value_before`, 
        `value_after`, 
        `who`, 
        `ts`
    )
    values
    (
        new.id,
        'u', 
        'name',
        old.name, 
        new.name,
        user(),
        now()
    );
end if;

if (old.age <> new.age) then
    insert into `my_table_log`
    (
        `id`, 
        `action`, 
        `column_name`, 
        `value_before`, 
        `value_after`, 
        `who`, 
        `ts`
    )
    values
    (
        new.id,
        'u', 
        'age',
        old.age, 
        old.age,
        user(),
        now()
    );
end if;

end

但最好使插入存储过程以避免重复:

create procedure `log_insert`
(
    id int(11),
    `action` char,
    column_name varchar(255),
    value_before varchar(255),
    value_after varchar(255)
)
begin

insert into `my_table_log`
(
    `id`, 
    `action`, 
    `column_name`, 
    `value_before`, 
    `value_after`, 
    `who`, 
    `ts`
)
values
(
    id,
    `action`, 
    column_name,
    value_before, 
    value_after,
    user(),
    now()
);

end

并在你的触发器中调用它:

create trigger `log_update` 
after update on `my_table` 
for each row
begin

if (old.name <> new.name) then
    call log_insert
    (
        new.id,
        'u', 
        'name',
        old.name, 
        new.name
    );
end if;

if (old.age <> new.age) then
    call log_insert
    (
        new.id,
        'u', 
        'age',
        old.age, 
        new.age
    );
end if;

end

您可以重复使用存储过程来记录插入和删除触发器中的事件。

使shure在my_table_log中使用复合主键以允许对多个列进行更新。我至少使用了:

primary key(id,column_name,who,ts).

或者使用专用的单列主键来避免主键中的varchars以获得更好的性能。

答案 1 :(得分:0)

另一种方法是将新值与user()和now():

一起记录下来
create table my_table_log 
(   id ...
,   name ...
,   age ...
,   action ...
,   who ...
,   ts ... )

要确定更改内容,请与上一行进行比较。

然而,在某个时间点确定行的样子是相当昂贵的,您必须在该时间点之前找到最后一个版本。使这更容易的另一个模型是跟踪每行的begin_ts和end_ts:

create table my_table_log 
(   id ...
,   name ...
,   age ...
,   action ...
,   who ...
,   begin_ts ... 
,   end_ts  ...)

插入触发器使用begin_ts = now()和end_ts = null添加行的副本。更新触发器更新end_ts = now(),其中end_ts为null并插入类似于insert触发器的行。删除触发器更新end_ts,并可能与删除该行的人一起添加副本。确定ts t处的行是where t between start_ts and end_ts

的问题