SQL数据库日期范围

时间:2013-04-25 15:51:53

标签: sql sql-server-2008 sql-date-functions

我有一张可以保存状态更新的平面表。

这些更新以以下格式存储:

  

AgreementID | StatusID | StatusDate

来源数据:

AgreementID StatusID    StatusDate
109         1           14/01/2013 15:00:33
109         2           14/01/2013 15:01:28
109         2           14/01/2013 15:01:28
109         2           14/01/2013 15:02:42
109         2           26/02/2013 16:27:38
109         2           26/02/2013 16:27:45
109         8           19/02/2013 13:57:33
109         8           04/03/2013 16:46:29
109         8           18/03/2013 14:08:12
109         8           18/03/2013 14:47:00
109         8           18/03/2013 14:48:46
109         9           26/03/2013 15:41:51

我需要的是在日期范围内映射协议状态,协议可以具有相同StatusID的多个状态更新,但是一旦协议进入下一个StatusID,它就不能退回到先前的状态ID。

对于最后一个状态,日期范围应为StatusDate To Date。

我有以下代码,但结果并没有给我我想要的东西......

SELECT     
    AgreementID, 
    CONVERT(datetime, CONVERT(varchar(10), StatusDate, 103), 103) AS StatusDate, 
    CONVERT(datetime, CONVERT(varchar(10), StatusDate, 103), 103) AS DateFrom, 
    CASE WHEN DateTo IS NULL THEN CONVERT(datetime, CONVERT(varchar(10), GETDATE(), 103), 103) ELSE CONVERT(datetime, CONVERT(varchar(10), DateTo, 103), 103) END AS DateTo, 
    StatusID
FROM         
    (
     SELECT     
        AgreementID, 
        StatusID, 
        StatusDate, 
        (SELECT TOP (1) StatusDate FROM TblStatusUpdates AS SU WHERE SU.AgreementID = U.AgreementID AND SU.StatusDate > U.StatusDate ORDER BY StatusID, StatusDate ASC) DateTo, 
        RN = ROW_NUMBER() OVER (Partition BY AgreementID ORDER BY StatusDate)
     FROM         
        (
         SELECT     
            AgreementID, 
            StatusID, 
            MIN(StatusDate) AS StatusDate
         FROM          
            TblStatusUpdates
         GROUP BY 
            AgreementID, StatusID
        ) AS U
    ) AS A 

以下是此查询的示例结果:

AgreementID StatusDate  DateFrom    DateTo      StatusID
109         14/01/2013  14/01/2013  14/01/2013  1
109         14/01/2013  14/01/2013  14/01/2013  2
109         19/02/2013  19/02/2013  26/02/2013  8
109         26/03/2013  26/03/2013  25/04/2013  9

正如您所看到的,Date To Value不正确,它应始终运行到下一个状态ID的前一天。

所以在这个例子中,状态2应该从19/02/2013到18/02/13

运行

任何建议都会很棒。谢谢。

3 个答案:

答案 0 :(得分:0)

如果您使用的是SQL Server 2012,则可以执行以下操作:

with agst as
     (select AgreementID, 
             CONVERT(datetime, CONVERT(varchar(10), min(StatusDate), 103), 103) AS StatusDate, 
             CONVERT(datetime, CONVERT(varchar(10), min(StatusDate), 103), 103) AS DateFrom, 
             StatusID
      from TblStatusUpdates
      group by AgreementID, StatusID
     )
select agst.*,
       lead(datefrom) over (partition by AgreementId, statusId order by DateFrom) - 1 as DateTo
from agst

我认为我通过使用聚合来简化StatusDate / MinDate的计算,聚合是agst common-table-expression。 lead()函数只是将下一个值拉入行中。

您可以使用相关子查询执行类似操作。这是那个版本:

with agst as
     (select AgreementID, 
             CONVERT(datetime, CONVERT(varchar(10), min(StatusDate), 103), 103) AS StatusDate, 
             CONVERT(datetime, CONVERT(varchar(10), max(StatusDate), 103), 103) AS DateFrom, 
             StatusID
      from TblStatusUpdates
      group by AgreementID, StatusID
     )
select agst.*,
       (select top 1 DateFrom
        from agst agst2
        where agst2.agreementId = agst.agreementid and
              agst2.StatusID = agst.StatusID and
              agst2.DateFrom > agst.DateFrom
        order by DateFrom desc
       ) - 1 as DateTo
from agst

答案 1 :(得分:0)

快速更新这个,我试图过于复杂,无法得到我需要的答案。

这是我现在的代码:

SELECT
     AgreementID, 
     StatusID,
     DateFrom,
     CASE WHEN DateTo IS NOT NULL THEN DATEADD(S, -1, DateTo) ELSE GETDATE() END AS DateTo
FROM
    (
     SELECT 
        AgreementID, 
        StatusID, 
        MIN(CONVERT(datetime,StatusDate,103)) as DateFrom, 
        (SELECT TOP(1) StatusDate FROM TblStatusUpdates AS B WHERE B.StatusID > A.StatusID ORDER BY StatusID ASC, StatusDate ASC) AS DateTo
     FROM 
        TblStatusUpdates AS A
     GROUP BY 
        AgreementID, 
        StatusID
    ) AS C

这给了我以下结果:

AgreementID StatusID    DateFrom                  DateTo
109         1           2013-01-14 15:00:33.360   2013-01-14 15:01:27.393
109         2           2013-01-14 15:01:28.393   2013-02-19 13:57:32.437
109         8           2013-02-19 13:57:33.437   2013-03-26 15:41:49.843
109         9           2013-03-26 15:41:50.843   2013-04-26 10:34:13.860

谢谢大家的建议。

答案 2 :(得分:-1)

希望这就是你要找的东西。

SQL FIDDLE