2014-03-12 62 views
0

使用SQL Server 2012.每天晚上,數據倉庫負載會填充貸款經歷的里程碑日期表。數據如下所示:從一系列日期開始的持續時間 - sql-server

CREATE TABLE TestData (LoanKey int, MilestoneCompletedDate datetime, Duration int) 

INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-16 16:51:56.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-18 15:11:29.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-23 16:21:59.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-28 14:52:00.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-08-26 10:53:37.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-09-19 15:16:38.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-09-20 08:31:38.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-08 15:56:05.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-16 16:11:10.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-10-09 11:20:35.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (2, '2013-09-10 11:15:09.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-06-03 16:22:32.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-06-21 14:46:24.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-08-30 10:03:08.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-08-30 13:55:17.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-09-03 15:28:22.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-09-04 09:30:08.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-09-12 10:44:46.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-09-25 16:06:43.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-06-24 11:59:25.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-09-25 16:06:43.000') 
INSERT TestData (LoanKey, MilestoneCompletedDate) VALUES (42, '2013-01-17 15:06:14.000') 

數據加載後,我想更新「持續時間」字段。下面是一些僞代碼:

UPDATE TestData SET Duration = 'Find the DateDiff between the current rows MilestoneCompletedDate and the next greatest milestone completion date for the same loan' 

我可以生成與PARTITION BY和ORDER BY行號:

SELECT 
    LoanKey, 
    MilestoneCompletedDate, 
    ROW_NUMBER() OVER (PARTITION BY LoanKey ORDER BY MilestoneCompletedDate DESC) AS SequenceNumber 
FROM 
    [dbo].[TestData] 

在哪裏何去何從填充時段的任何想法?

謝謝你看!

回答

1

既然你的SQL Server 2012上,您可以使用LEAD:在SQL Server

從相同的結果一行後續不使用的訪問設置數據自2012年加盟提供LEAD訪問當前行之後的給定物理偏移處的行。

;With leads as (
    select *, LEAD(MilestoneCompletedDate) OVER 
       (PARTITION BY LoanKey 
        ORDER BY MilestoneCompletedDate) as NextCompletion 
    from TestData 
) 
UPDATE leads SET Duration =DATEDIFF(second,MilestoneCompletedDate,NextCompletion) 

select * from TestData 

產地:

LoanKey  MilestoneCompletedDate Duration 
----------- ----------------------- ----------- 
2   2013-10-16 16:51:56.000 166773 
2   2013-10-18 15:11:29.000 436230 
2   2013-10-23 16:21:59.000 426601 
2   2013-10-28 14:52:00.000 NULL 
2   2013-08-26 10:53:37.000 1297292 
2   2013-09-19 15:16:38.000 62100 
2   2013-09-20 08:31:38.000 1581867 
2   2013-10-08 15:56:05.000 69870 
2   2013-10-16 16:11:10.000 2446 
2   2013-10-09 11:20:35.000 622235 
2   2013-09-10 11:15:09.000 792089 
42   2013-06-03 16:22:32.000 1549432 
42   2013-06-21 14:46:24.000 249181 
42   2013-08-30 10:03:08.000 13929 
42   2013-08-30 13:55:17.000 351185 
42   2013-09-03 15:28:22.000 64906 
42   2013-09-04 09:30:08.000 695678 
42   2013-09-12 10:44:46.000 1142517 
42   2013-09-25 16:06:43.000 0 
42   2013-06-24 11:59:25.000 5781823 
42   2013-09-25 16:06:43.000 NULL 
42   2013-01-17 15:06:14.000 11841378 

在SQL Server的早期版本,我會考慮你的ROW_NUMBER()基於查詢並做了一些自加入該被提及的LEAD文檔:

;With Ordered as (
    SELECT 
     LoanKey, 
     MilestoneCompletedDate, 
     ROW_NUMBER() OVER (PARTITION BY LoanKey 
       ORDER BY MilestoneCompletedDate DESC) AS SequenceNumber 
    FROM 
     [dbo].[TestData] 
) 
UPDATE o1 SET Duration = 
    DATEDIFF(second,o1.MilestoneCompletedDate,o2.MilestoneCompletedDate) 
FROM Ordered o1 
LEFT JOIN Ordered o2 
ON o1.LoanKey = o2.LoanKey and o1.SequenceNumber = o2.SequenceNumber - 1 
+0

Gah的問題有一個簡單的解決方案,很好的答案,我完全沒有注意2008年後的功能,「LEAD」是一個很棒的功能。 – OGHaza

+0

謝謝你的迴應! LEAD方法存在一個問題。由LoanKey = 2和MilestoneCompletedDate = 2013-10-28定義的行的持續時間爲NULL。這是貸款的最後一個里程碑。上一個里程碑是2013-10-23,因此持續時間應該是5.看起來正確的持續時間都向下移動了一個里程碑。第二種方法將Duration添加到Ordered表中,並在DATEDIFF中反轉02和01。 – jjm

+0

@jjm - 那是因爲你談到了一排排,然後找到下一個最好的排,所以我認爲你想根據下一個日期更新當前排。但從你的評論中,你想要的(對於任何特定的行)是找到* previous *行。在這種情況下,或者將'LAG'換成'LEAD'或者(邏輯上相同)將'ORDER BY'改爲'ASC'而不是'DESC'。 –

1

這應該做的工作,改變HOUR到你喜歡的任何單位:

UPDATE a 
SET Duration = DATEDIFF(HOUR 
         ,(SELECT MAX(b.MilestoneCompletedDate) 
          FROM TestData b 
          WHERE b.MilestoneCompletedDate < a.MilestoneCompletedDate 
          AND b.LoanKey = a.LoanKey) 
         ,a.MilestoneCompletedDate) 
FROM TestData a 
WHERE Duration IS NULL 

SQLFiddle似乎在此刻SQL服務器被打破,所以不能發佈小提琴,但前4行(通過LoadKey, MilestoneCompletedDate訂購)更新後的問世:

LoanKey MilestoneCompletedDate Duration 
2  2013-08-26 10:53:37.000 NULL 
2  2013-09-10 11:15:09.000 361 
2  2013-09-19 15:16:38.000 220 
2  2013-09-20 08:31:38.000 17 

或者,你可以使用ROW_NUMBER像自己所想的,但它是一個有些凌亂。例如:

;WITH cte AS (
    SELECT 
     LoanKey, 
     MilestoneCompletedDate, 
     Duration, 
     ROW_NUMBER() OVER (PARTITION BY LoanKey 
          ORDER BY MilestoneCompletedDate ASC) AS SeqNum 
    FROM @TestData 
    WHERE duration IS NULL 
) 
UPDATE a 
SET Duration = DATEDIFF(HOUR 
         ,b.MilestoneCompletedDate 
         ,a.MilestoneCompletedDate) 
FROM cte a 
INNER JOIN cte b ON a.LoanKey = b.LoanKey 
       AND a.SeqNum = b.SeqNum + 1 

它返回相同的結果集。

+0

是否行號實際上計算兩次或者不是在優化器的支配下,而且除非出現性能問題,否則我不會在執行計劃中查找它。 –

+0

公平競賽,刪除。在過去我把CTE鏈接起來的時候,我看到了儘可能少的選擇,但我意識到沒有一個通用的規則。 – OGHaza

+0

您的第一種方法適用於我,我喜歡它的簡單性。非常感謝你! – jjm

相關問題