从审计表中查找更改

Posted

技术标签:

【中文标题】从审计表中查找更改【英文标题】:Find changes from an audit table 【发布时间】:2018-11-30 12:12:51 【问题描述】:

我在如下审计表中有数据。 Fiddle 1, Fiddle 2

我需要从此表中获取更新的列和数据详细信息。

预期结果是:

员工姓名:从 Jone 到 Jhone

员工年龄:25-20岁

员工姓名:从 Jhonny 到 Jone,员工年龄:从 18 到 25

我怎样才能做到这一点?

更新

当记录更新时,我在审计表中插入两行。第一个记录为Old(auditDataState),包含更新前的数据,第二个记录为New(auditDataState),包含更新后的数据。

因此,每次更新在审计表中都有两条记录,分别为 OldNew,具有旧值和新值。

我需要根据审计表中的updateColumns 从审计表中获取更新的数据。(我将更新的列存储在 updateColumns 列中)。

我不需要第一行是Employee Name : from Jone to Jhone。只需要识别更新的值。

【问题讨论】:

您是否希望 SQL 中第一列的值是 'Employee Name : from Jone to Jhone'?这并不容易。特别是当您稍后混合数据类型时(我假设empAgeint)。您最好提供一个包含两个值(旧值和新值)的数据集并使用您的应用程序来执行显示格式。这是在您的 DBMS 中完成的一项糟糕的任务。 @Larnu 感谢您的回复。请检查更新的问题。我不需要第一行是Employee Name : from Jone to Jhone。只需要识别更新的值。那我就可以做显示格式了。 你没有说你使用的是哪个版本。从 2016 年起,临时表非常适合您的需求。 查看您提供的数据,所有的变化同时发生。我们如何确定哪个“新”行与哪个“旧”行相关? 另外,这个解决方案需要多通用?由于您的 updateColumns 值与要更新的实际列名不对应,因此需要手动映射或检查每个潜在的数据列。 【参考方案1】:

这将提供您问题中指定的结果,尽管它远非明智或可扩展的解决方案。如果可能的话,我建议您完全重新审视您的变更审计:

declare @EmpAudit table (
      empID int
    , empName varchar(50)
    , empAge int
    , auditDataState varchar(50)
    , auditDMLAction varchar(50)
    , auditUser varchar(50)
    , auditDateTime datetime
    , updateColumns varchar(50)
);

insert into @EmpAudit values
      (1, 'Alex', 22, 'New', 'Insert','c@a.com',getdate(),''),
      (2, 'Jhonny', 18, 'New', 'Insert','c@a.com',getdate()-0.5,''),

      (2, 'Jhonny', 18, 'Old', 'Update','b@a.com',getdate()-1,'Employee Name, Employee Age'),
      (2, 'Jone', 25, 'New', 'Update','b@a.com',getdate()-1.5,'Employee Name, Employee Age'),

      (2, 'Jone', 25, 'Old', 'Update','a@a.com',getdate()-2,'Employee Age'),
      (2, 'Jone', 30, 'New', 'Update','a@a.com',getdate()-2.5,'Employee Age'),

      (2, 'Jone', 30, 'Old', 'Update','a@a.com',getdate()-3,'Employee Age'),
      (2, 'Jone', 20, 'New', 'Update','a@a.com',getdate()-3.5,'Employee Age'),

      (2, 'Jone', 20, 'Old', 'Update','a@a.com',getdate()-4,'Employee Name'),
      (2, 'Jhone', 20, 'New', 'Update','a@a.com',getdate()-4.5,'Employee Name');

with d as
(
    select empID
            ,empName
            ,empAge
            ,auditDataState
            ,auditDMLAction
            ,auditUser
            ,auditDateTime
            ,updateColumns
            ,row_number() over (partition by empID order by auditDateTime) as rn
    from @EmpAudit
)
select case when o.empName <> n.empName then 'Employee Name : from ' + o.empName + ' to ' + n.empName else '' end
      +case when charindex(',',o.UpdateColumns) > 0 then ', ' else '' end
      +case when o.empAge <> n.empAge then 'Employee Age : from ' + cast(o.empAge as varchar(3)) + ' to ' + cast(n.empAge as varchar(3)) else '' end as Change
from d as o
    join d as n
        on o.empID = n.empID
            and o.updateColumns = n.updateColumns
            and o.rn = n.rn+1
            and n.auditDataState = 'New'
where o.auditDataState = 'Old';

输出:

Change
-----------------------------------------------------------------
Employee Name : from Jone to Jhone
Employee Age : from 30 to 20
Employee Age : from 25 to 30
Employee Name : from Jhonny to Jone, Employee Age : from 18 to 25

【讨论】:

感谢您的回答。这就是我一直在寻找的答案。顺便说一句,这种情况存在问题。 rextester.com/HNVGB67216 @Bishan 不用担心 :) 如果这是您需要的答案,请将其标记为这样,以便其他 Stack Overflow 用户受益。 是的。这是我一直在寻找的答案。顺便说一句,在此示例中的情况下仍然无法返回正确的数据。 rextester.com/HNVGB67216 @Bishan 当然有一个问题,你没有在你的变更审计过程中提供足够的信息来指定变更的顺序。这就是为什么我建议你重新审视你的整个过程。 旧 = 30,新 = 20

以上是关于从审计表中查找更改的主要内容,如果未能解决你的问题,请参考以下文章

通过 Excel 用户窗体编辑 Access 数据库时跟踪更改(创建审计跟踪)

将 MERGE 语句的更新列审计为不同表中的行

外键的审计触发器

在 Oracle 中审计 DML 更改

Hibernate Envers:如何从我的审计表中删除条目?

已审核,查找属于用户的审核