2016-06-13 53 views
0

我試圖將CustomerAudit表中的數據轉換爲CustomerHistory中描述的格式。 CustomerAudit記錄對客戶屬性的更改(添加,編輯,刪除)。 (姓名,地址,電話)。 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我很感激任何幫助,想出一個合理的執行解決方案。

謝謝

回答

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在LAG()上實施IGNORE NULLS選項,那麼這將很容易:

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) 

唉,它沒有。您可以嘗試: