我有一个每天晚上都会插入的表,它是数据的快照。在任何时间点,列中的数据都可能会发生变化(AccountNo 保持不变,RunKey 增加 1,RunDate 增加 1 天;所有其他列都可以临时更改)。以下是数据外观的示例:
|AccountNo | RunKey | RunDate | Address | Salary | PromotionDate| ---------------------------------------------------------------------------- | 12345 | 2 | 06/20/2017 | 123 Main Street | 60,000 | 01/15/2017 | | 12345 | 3 | 06/21/2017 | 123 Main Street | 60,000 | 01/15/2017 | | 12345 | 4 | 06/22/2017 | 123 Main Street | 65,000 | 06/21/2017 |
使用 LAG 函数和 CASE 表达式,我能够确定何时发生更改(标志为 1 表示发生更改):
|AccountNo | RunKey | RunDate | Address | AddressLAG |AddressFlag| Salary | SalaryLAG |SalaryFlag| PromotionDate|PromotionDateLag|PromotionFlag| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | 12345 | 2 | 06/20/2017 | 123 Main Street | 123 Main Street | 0 | 60,000 | 60,000 | 0 | 01/15/2017 | 01/15/2017 | 0 | | 12345 | 3 | 06/21/2017 | 123 Main Street | 123 Main Street | 0 | 60,000 | 60,000 | 0 | 01/15/2017 | 01/15/2017 | 0 | | 12345 | 4 | 06/22/2017 | 123 Main Street | 123 Main Street | 0 | 65,000 | 60,000 | 1 | 01/15/2017 | 06/21/2017 | 1 |
我只需将更改的记录插入到新表中,新表将如下所示:
| RunKey | AccountNo | ChangedCol | PrevRunDate | RunDate | PrevValue | NewValue | ------------------------------------------------------------------------------------------- | 4 | 12345 | Salary | 06/21/2017 | 06/22/2017 | 60,000 | 65,000 | | 4 | 12345 | PromotionDate | 06/21/2017 | 06/22/2017 | 01/15/2017 | 06/21/2017 |
每列更改都会有一条新记录。因此,如果多个列发生更改,则每个更改都将记录在新行中。这是我需要帮助的地方,我不知道如何动态地将仅更改的列插入新表中。
最佳答案
因此,通常这是通过触发器来完成的。每当对表进行插入或更新时,都会对审计表进行后续插入。所以,我真的会调查一下。但是,如果您不想走这条路,或者这是一个无法添加触发器的第三方系统,您可以通过几种方式插入更改。一种快速的方法是使用 except。基本上,当记录不完全匹配时,它会将源表中的记录插入审计表中。这是一个例子。
declare @source table (
AccountNo int
,Address varchar(256)
,Salary decimal(16,4)
,PromotionDate datetime)
insert into @source
values
(12345,'123 Main Street',60000,'20170115')
declare @audit table (
AccountNo int
,Address varchar(256)
,Salary decimal(16,4)
,PromotionDate datetime
,RunDate datetime)
--load the audit table with the current version of the source table
insert into @audit
select *, getdate() from @source
--show that the tables match currently
select * from @source
select * from @audit
--insert into @audit if there are any changes (notice we haven't made any updates yet)
insert into @audit
select AccountNo, Address, Salary, PromotionDate, getdate() from @source
except
select AccountNo, Address, Salary, PromotionDate, getdate() from @audit
--show that a record WAS NOT inserted since there was no change. There is only 1 record, the orignal version
select * from @audit
--update the promotion and salary
update @source
set
PromotionDate = '20170331'
,Salary = '65000'
--insert into @audit if there are any changes
insert into @audit
select AccountNo, Address, Salary, PromotionDate, getdate() from @source
except
select AccountNo, Address, Salary, PromotionDate, getdate() from @audit
--show that a record was inserted since there was a change
select * from @audit
然后,您所要做的就是从 @audit 表中进行选择并按 RunDate 排序,您就可以轻松地快速看到更改的内容,而不是旋转数据并为每个帐户的每次更改保留 1 行。在此示例中,尽管工资和晋升数据发生了变化,但您仅看到 1 行额外的行。您可以使用 LEAD 和 LAG 函数,或者在顶部 1 上使用自连接,其中 RunDate < RunDate 来标记列是否发生更改,但实际上没有必要。
关于sql - SQL Server 2014中数据发生变化时如何提取列名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44708276/