2013-02-19 39 views
3

我正在使用SQL Server 2012並具有如下所示的值的表格。它填充了事件數據。使用SQL Server 2012的Last_Value()函數時忽略空值

FldType Date     Price Size 
-------------------------------------------- 
2  2012-08-22 00:02:01  9140 1048 
0  2012-08-22 00:02:02  9140 77 
1  2012-08-22 00:02:03  9150 281 
2  2012-08-22 00:02:04  9140 1090 
0  2012-08-22 00:02:05  9150 1 
1  2012-08-22 00:02:06  9150 324 
2  2012-08-22 00:02:07  9140 1063 

我想跟蹤最新的值對每個3種字段類型(0,1,2),以使最終的輸出如下所示。

Date    Price0 Size0 Price1 Size1 Price2 Size2 
----------------------------------------------------------------- 
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048 
2012-08-22 00:02:02 9140 77  NULL NULL 9140 1048 
2012-08-22 00:02:03 9140 77  9150 281  9140 1048 
2012-08-22 00:02:04 9140 77  9150 281  9140 1090 
2012-08-22 00:02:05 9150 1  9150 281  9140 1090 
2012-08-22 00:02:06 9150 1  9150 324  9140 1090 
2012-08-22 00:02:07 9150 1  9150 324  9140 1063 

不幸的是,它不忽略後續的空值,所以我得到了這個。

Date    Price0 Size0 Price1 Size1 Price2 Size2 
----------------------------------------------------------------- 
2012-08-22 00:02:01 NULL NULL NULL NULL 9140 1048 
2012-08-22 00:02:02 9140 77  NULL NULL NULL NULL  
2012-08-22 00:02:03 NULL NULL 9150 281  NULL NULL 
2012-08-22 00:02:04 NULL NULL NULL NULL 9140 1090 
2012-08-22 00:02:05 9150 1  NULL NULL NULL NULL  
2012-08-22 00:02:06 NULL NULL 9150 324  NULL NULL  
2012-08-22 00:02:07 NULL NULL NULL NULL 9140 1063 

我當前的查詢看起來像這樣

SELECT [Date], 
    LAST_VALUE(Price0) OVER (PARTITION BY FldType ORDER BY [Date]) AS Price0, 
    LAST_VALUE(Size0) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size0, 
    LAST_VALUE(Price1) OVER (PARTITION BY FldType ORDER BY [Date]) AS Price1, 
    LAST_VALUE(Size1) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size1, 
    LAST_VALUE(Price2) OVER (PARTITION BY FldType ORDER BY [Date]) AS Price2, 
    LAST_VALUE(Size2) OVER (PARTITION BY FldType ORDER BY [Date]) AS Size2 
FROM ( 
SELECT FldType, [Date], Price, Size, 
    CASE WHEN FldType = 0 THEN Price END as Price0, 
    CASE WHEN FldType = 0 THEN Size END as Size0, 
    CASE WHEN FldType = 1 THEN Price END as Price1, 
    CASE WHEN FldType = 1 THEN Size END as Size1, 
    CASE WHEN FldType = 2 THEN Price END as Price2, 
    CASE WHEN FldType = 2 THEN Size END as Size2 
FROM [RawData].[dbo].[Events] 
) as T1 
ORDER BY [Date] 

是否有某種方式有SQL Server 2012的確定最新的值時忽略空值?或者有更好的方法不使用函數?

總結我試圖實現兩件事。

  1. 拆分的PriceSize列到6列(2列×3字段類型)
  2. 跟蹤在每個這些列的最新值的。

任何建議將apprciated。

+1

** SQL ** =結構化的查詢語言,本身就是語言; ** SQL 2012 ** = 2012年的SQL語言標準(不一致); SQL ** Server ** 2012 = 2012版微軟** SQL Server **產品 – 2013-02-19 09:25:16

+0

@marc_S好點!感謝您的改變! – 2013-02-19 09:27:50

+0

編輯標題明確表示它是SQL Server 2012.這是重要的區別,因爲1)Oracle的SQL確實有一個忽略空值選項,並且2)在SQL Server 2012中有'ROWS'和'RANGE'選項可能有些用於尋找解決方案 – 2013-02-19 10:03:04

回答

4

我不確定你可以用LAST_VALUE做到這一點,除非你添加一個PIVOT也許。

此外,您需要分別對待尺寸和價格,因爲它們來自不同的行。所以,這實現了你想要分解的東西。

DECLARE @source TABLE (FldType int, DateCol DateTime, Price int, Size int); 

INSERT @source VALUES 
    (2, '2012-08-22 00:02:01', 9140, 1048),(0, '2012-08-22 00:02:02', 9140, 77), 
    (1, '2012-08-22 00:02:03', 9150, 281),(2, '2012-08-22 00:02:04', 9140, 1090), 
    (0, '2012-08-22 00:02:05', 9150, 1),(1, '2012-08-22 00:02:06', 9150, 324), 
    (2, '2012-08-22 00:02:07', 9140, 1063); 


SELECT 
    S.DateCol, Xp0.Price0, Xs0.Size0, Xp1.Price1, Xs1.Size1, Xp2.Price2, Xs2.Size2 
FROM 
    @source S 
    OUTER APPLY 
    (SELECT TOP 1 S0.Price AS Price0 FROM @source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xp0 
    OUTER APPLY 
    (SELECT TOP 1 S1.Price AS Price1 FROM @source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xp1 
    OUTER APPLY 
    (SELECT TOP 1 S2.Price AS Price2 FROM @source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xp2 
    OUTER APPLY 
    (SELECT TOP 1 S0.Size AS Size0 FROM @source S0 WHERE S0.FldType = 0 AND S0.DateCol <= S.DateCol ORDER BY S0.DateCol DESC) Xs0 
    OUTER APPLY 
    (SELECT TOP 1 S1.Size AS Size1 FROM @source S1 WHERE S1.FldType = 1 AND S1.DateCol <= S.DateCol ORDER BY S1.DateCol DESC) Xs1 
    OUTER APPLY 
    (SELECT TOP 1 S2.Size AS Size2 FROM @source S2 WHERE S2.FldType = 2 AND S2.DateCol <= S.DateCol ORDER BY S2.DateCol DESC) Xs2 
ORDER BY 
    DateCol; 

另一種方法是通過觸發器或一些ETL維護一個單獨的表,它爲您完成總結。

+1

謝謝!這確實給了我我需要的東西。我沒有意識到OUTER APPLY方法。 < - 學到了全新的東西! – 2013-02-19 11:30:27

+1

@ChrisTarn,基本上,你需要''LAST_VALUE''和'IGNORE NULL'子句,但不幸的是SQL Server沒有實現它(例如Oracle)。由於爲每一行運行子查詢,「OUTER APPLY」方法可能相當昂貴。 Itzik Ben-Gan在他的[The Last Non NULL Puzzle](http://sqlmag.com/t-sql/last-non-null-puzzle)中展示了它如何更有效地完成。 – 2017-10-20 02:42:28