如何检索以前的非Null值

时间:2016-06-13 00:15:57

标签: sql sql-server-2012

我正在尝试将 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.我很感激任何帮助,以提出一个合理执行的解决方案。

谢谢

1 个答案:

答案 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)
唉,它没有。你可以尝试: