2014-03-12 29 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

相关问题