我有一张可以保存状态更新的平面表。
这些更新以以下格式存储:
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
运行任何建议都会很棒。谢谢。
答案 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)
希望这就是你要找的东西。