2012-05-18 47 views
3

我在T-SQL中有一個非常具體的問題。T-SQL查詢更新空值

如果我能解決這個例子案例,我給你我想我能解決我的原始案例。

上述表這樣的數據:

DECLARE @Test TABLE 
(
    Value INT 
    ,Date DATETIME2(7) 
); 

INSERT INTO @Test 
VALUES 
(NULL, '2011-01-01 10:00'), 
(NULL, '2011-01-01 11:00'), 
(2, '2011-01-01 12:00'), 
(NULL, '2011-01-01 13:00'), 
(3, '2011-01-01 14:00'), 
(NULL, '2011-01-01 15:00'), 
(NULL, '2011-01-01 16:00'), 
(4, '2011-01-01 17:00'), 
(NULL, '2011-01-01 18:00'), 
(5, '2011-01-01 19:00'), 
(6, '2011-01-01 20:00') 

,我需要選擇輸出:

Value Date 
2  2011-01-01 10:00 
2  2011-01-01 11:00 
2  2011-01-01 12:00 
2  2011-01-01 13:00 
3  2011-01-01 14:00 
3  2011-01-01 15:00 
3  2011-01-01 16:00 
4  2011-01-01 17:00 
4  2011-01-01 18:00 
5  2011-01-01 19:00 
6  2011-01-01 20:00 

給予一定的解釋。如果值爲NULL,則需要使用前一小時的值更新。如果一行中有多個空值,則非空值最近的小時間傳播並填充所有這些空值。此外,如果一天中的第一個小時爲空,則在這種情況下,非空值當天的最早小時向下傳播,如2。在你的情況下,你可以假設至少有一個值是非空值。

我的目標是用Common table表達式或類似的東西來解決這個問題。用光標的方式,我想如果我嘗試一下,我會在短時間內得到解決方案,但是到目前爲止,我對CTE和遞歸CTE的嘗試失敗了。

+0

你有什麼索引樹d?發佈迄今爲止已完成的工作很有幫助 - 您可能會接近並需要一些建議來糾正您的現有查詢。 – Taryn

+0

由於我不知道在一行中有多少個空值,因此前一小時的單個連接是不夠的。在那裏,我想也許我可以通過某種方式用遞歸來解決它。我只使用CTE遞歸經典的層次結構方式,但我的想法是,如果我可以每次在遞歸中更新一個空值,也許我可以填充它們。事實上,當我嘗試這個想法時,我很早就失去了它。所以我不相信這會有很多幫助。 – John

+0

在你的例子中,隨着Date的增加,Value的值不減。這是巧合,還是會一直如此? – AakashM

回答

3

由於您的情況並不總是相同,所以這有點難度。在你的例子中,前兩行需要從第一個值中獲取它們的值,並在以後的日期中獲取它們的值,而在其他情況下,它們需要從之前的日期中獲取值。如果你總是需要尋找以前的日期,你可以簡單的做到這一點查詢:

SELECT B.Value, 
     A.[Date] 
FROM @Test A 
OUTER APPLY (SELECT TOP 1 * 
      FROM @Test 
      WHERE [Date] <= A.[Date] AND Value IS NOT NULL 
      ORDER BY [Date] DESC) B 

但在你的情況,我認爲你需要這個來代替:

SELECT ISNULL(B.Value,C.Value) Value, 
     A.[Date] 
FROM @Test A 
OUTER APPLY (SELECT TOP 1 * 
      FROM @Test 
      WHERE [Date] <= A.[Date] AND Value IS NOT NULL 
      ORDER BY [Date] DESC) B 
OUTER APPLY (SELECT TOP 1 * 
      FROM @Test 
      WHERE Value IS NOT NULL 
      ORDER BY [Date]) C 
+0

實際上,當我接受其他答案時,我有點快速。這只是與我每小時增加的樣本數據一起工作。 這是正確的答案,它給了我正確的結果。但是我的真實數據存在可怕的性能問題。 有什麼建議你可以做些什麼來提高性能? – John

+0

@John - 是的,因爲你至少要經歷兩次「測試」表,所以它肯定會有不好的表現。你知道,第二個'OUTER APPLY'只在第一個值爲NULL時出現,也許你可以更好地避免這種情況。而且我假設你至少在「日期」列上有一個索引。 – Lamak

2

試試這個:

select 
    t.value, t.date 
     ,COALESCE(t.value 
       ,(select MAX(tt.value) from @Test tt WHERE t.Date>tt.Date) 
       ,(SELECT MIN(ttt.Value) FROM @Test ttt Where ttt.Date IS NOT NULL) 
       ) AS UseValue 
    from @Test t 

OUTPUT:

value  date     UseValue 
----------- ----------------------- ----------- 
NULL  2011-01-01 10:00:00.000 2 
NULL  2011-01-01 11:00:00.000 2 
2   2011-01-01 12:00:00.000 2 
NULL  2011-01-01 13:00:00.000 2 
3   2011-01-01 14:00:00.000 3 
NULL  2011-01-01 15:00:00.000 3 
NULL  2011-01-01 16:00:00.000 3 
4   2011-01-01 17:00:00.000 4 
NULL  2011-01-01 18:00:00.000 4 
5   2011-01-01 19:00:00.000 5 
6   2011-01-01 20:00:00.000 6 
+0

我最初接受了這個答案,但是我實際上使用了上面的其他解決方案,因爲我認爲它們都在工作。但是現在,當我在解決其他解決方案時遇到了一些性能問題時,我開始嘗試這個方法,發現它不起作用。它僅適用於此示例,因爲值每小時都在增加。試着將這些值洗牌一下,看看會發生什麼:) – John

+0

@John,如果只有你有一個適當的PK! –