我正在尝试将 CustomerAudit 表格中的数据转换为 CustomerHistory 中描述的格式。 CustomerAudit记录对Customer属性的更改(添加,编辑,删除)。 (姓名,地址,电话)。 CustomerHistory是一个快照表,列出客户在更改时在给定日期的属性。
表: CustomerAudit
Id Entity EntityId Field OldValue NewValue Type AuditDate
1 Customer 1 Name NULL Joe Add 2016-01-01
2 Customer 1 Phone NULL 567-54-3332 Add 2016-01-01
3 Customer 1 Address NULL 456 Centre Add 2016-01-01
4 Customer 1 Address 456 Centre 123 Main Edit 2016-01-02
5 Customer 1 Phone 567-54-3332 843-43-1230 Edit 2016-01-03
6 Customer 1 Phone 843-43-1230 NULL Delete 2016-01-04
表: CustomerHistory
EntityId Name Address Phone AuditDate
1 Joe 456 Centre 567-54-3332 2016-01-01
1 Joe 123 Main 567-54-3332 2016-01-02
1 Joe 123 Main 843-43-1230 2016-01-03
1 Joe 123 Main NULL 2016-01-04
我使用了CROSS APPLY,它在3列中表现良好,但在30页表现不佳。我正在使用SQL Server 2012.我很感激任何帮助,以提出一个合理执行的解决方案。
谢谢
答案 0 :(得分:1)
您可以使用条件聚合或数据透视来更改数据:
select entityid, auditdate,
max(case when field = 'Name' then newvalue end) as name,
max(case when field = 'Address' then newvalue end) as address,
max(case when field = 'Phone' then newvalue end) as phone
from CustomerAudit
group by entityid, auditdate;
然后您要填写NULL
s的先前值:
如果SQL Server在IGNORE NULLS
上实现了LAG()
选项,那么这很容易:
with ea as (
select entityid, auditdate,
max(case when field = 'Name' then newvalue end) as name,
max(case when field = 'Address' then newvalue end) as address,
max(case when field = 'Phone' then newvalue end) as phone
from CustomerAudit
group by entityid, auditdate
)
select entityid, auditdate,
coalesce(name, lag(name ignore nulls) over (partition by entityid order by auditdate) as name,
. . .
from ea;
但生活并不那么容易。您已尝试过outer apply
方法。以下是其他一些方法
一种蛮力方式只是看不同的滞后量,看起来像这样:
select entityid, auditdate,
coalesce(name,
lag(name, 1) over (partition by entityid order by auditdate),
lag(name, 2) over (partition by entityid order by auditdate),
lag(name, 3) over (partition by entityid order by auditdate),
lag(name, 4) over (partition by entityid order by auditdate)
) as name
. . .
from ea;
当然,此版本假定值位于最后五行。
另一种粗俗方式是使用字符串操作:
select entityid, auditdate,
coalesce(name,
substring(max(left('00000000' + cast(id as varchar(8)), 8) + name) over (partition by entityid order by auditdate), 9, 100)
) as name
. . .
from ea;
这对于非字符串数据类型来说比较棘手。
另一种方法使用重复的join
s:
select entityid, auditdate,
max(case when name is not null then id end) over (partition by entityid order by auditdate) as nameid,
. . .
然后,您需要join
返回原始表以获取实际的name
值。这应该很快,因为join
可能使用索引列。但是查询有点复杂。
LAG(address IGNORE NULLS) OVER (PARTITION BY EntityId ORDER BY Id)
唉,它没有。你可以尝试: