从日期列表中创建日期范围列表

时间:2013-03-25 14:15:01

标签: sql-server

我们目前按以下方式存储付款时间表:

Item No | Due Date   | Amount Due
108     | 2013-02-01 | 60.00
108     | 2013-02-26 | 60.00
108     | 2013-03-01 | 60.00
108     | 2013-03-15 | 60.00

注意:日期之间的差异是不一致的,即某些项目可能是几周,四周或几个月。

理想情况下,我需要解决的是如何将上表重新查询为以下格式:

Item No | Due Date   | Date From  | Date To    | Amount Due
108     | 2013-02-01 | 2013-01-14 | 2013-02-25 | 60.00
108     | 2013-02-26 | 2013-02-26 | 2013-02-28 | 60.00
108     | 2013-03-01 | 2013-03-01 | 2013-03-14 | 60.00
108     | 2013-03-15 | 2013-03-15 | 2013-03-25 | 60.00

为了实现这一目标,额外的两个日期将是开始日期(2013-01-14)和今天的日期(2013-03-25)。

每个范围应从原始截止日期到下一个截止日期前一天。

任何建议都将不胜感激。


更新

这是我到目前为止所尝试的内容:

WITH 
    CTE_Repayments(AgreementID, DueDate, AmountDue)
AS 
    (
    -- Anchor Member Definition
        SELECT 
            AgreementID, StartDate, CONVERT(DECIMAL(9,2),0.00)
        FROM
            Loans AS L
        WHERE
            L.AgreementID = 111
        UNION ALL
    -- Recursive Member Definition
        SELECT
            RB.AgreementID, RB.DueDate, CONVERT(Decimal(9,2),RB.AmountDue)
        FROM
            (
                SELECT *
                FROM RepaymentBreakdown
                WHERE AgreementID = 111
            ) AS RB
        INNER JOIN
            CTE_Repayments AS R
            ON RB.AgreementID = R.AgreementID
    )

-- Statement that Executes CTE
SELECT AgreementID, DueDate,  AmountDue
FROM CTE_Repayments

但这不起作用。

我假设我需要添加一个以开始日期为锚点成员的记录。

好了,现在返回带有上述修改代码的数据。

我现在遇到的问题是结果集不限于来自Anchor的AgreementID,我收到错误:

  

Msg 530,Level 16,State 1,Line 1   声明终止。在语句完成之前,最大递归100已经用尽。

2 个答案:

答案 0 :(得分:2)

您的错误是您的语句达到默认递归限制100的结果。可以使用MAXRECURSION query hint更改此错误。要使用没有声明限制的提示,您的语句将如下所示:

-- Statement that Executes CTE
SELECT AgreementID, DueDate,  AmountDue
FROM CTE_Repayments
OPTION (MAXRECURSION 0)

警告非常小心,对递归没有限制。这个限制适用于短路无限递归循环。根据数据的外观,您的查询可能很容易转出并产生其他问题。我建议逐步将MAXRECURSION增加到100以上,以找到合适的上限。在将此代码投入生产之前,一定要对此进行测试。

答案 1 :(得分:1)

在CTE中可能有一种更优雅的方式,但这是我的解决方案。

WITH cte (rowNo, itemNo, dueDate, amountDue) AS
( 
  SELECT ROW_NUMBER() OVER(ORDER BY [Due Date]) rowNo, 
    [Item No], [Due Date], [Amount Due]
  FROM loans
)
SELECT a.itemNo, a.dueDate,
  CASE WHEN c.dueDate IS NULL THEN '2013-01-14'
    ELSE a.dueDate END AS dateFrom,
  CASE WHEN b.dueDate IS NULL THEN '2013-03-25'
    ELSE DATEADD(day, -1, b.dueDate) END AS dateTo,
  a.amountDue
FROM cte AS a
LEFT JOIN cte AS b ON b.rowNo = a.rowNo + 1
LEFT JOIN cte AS c ON c.rowNo = a.rowNo - 1

<强>结果

| ITEMNO |                         DUEDATE |                        DATEFROM |                          DATETO | AMOUNTDUE |
----------------------------------------------------------------------------------------------------------------------------
|    108 | February, 01 2013 00:00:00+0000 |  January, 14 2013 00:00:00+0000 | February, 25 2013 00:00:00+0000 |        60 |
|    108 | February, 26 2013 00:00:00+0000 | February, 26 2013 00:00:00+0000 | February, 28 2013 00:00:00+0000 |        60 |
|    108 |    March, 01 2013 00:00:00+0000 |    March, 01 2013 00:00:00+0000 |    March, 14 2013 00:00:00+0000 |        60 |
|    108 |    March, 15 2013 00:00:00+0000 |    March, 15 2013 00:00:00+0000 |    March, 25 2013 00:00:00+0000 |        60 |

See the demo

相关问题