Sql server 从日期列表创建日期范围列表

Sql server 从日期列表创建日期范围列表,sql-server,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 | D

我们目前存储的付款计划如下:

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
但这是行不通的

我假设我需要添加一条记录,记录的起始日期为锚定成员

好的,它现在返回带有上面修改代码的数据

我现在的问题是,结果集不限于来自锚的AgreementID,我得到一个错误:

Msg 530,16级,状态1,第1行 声明终止了。在语句完成之前,已耗尽最大递归100


在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 | |项目编号|到期日|日期从|日期到|应付金额| ---------------------------------------------------------------------------------------------------------------------------- |108 | 2013年2月1日00:00:00+0000 | 2013年1月14日00:00:00+0000 | 2013年2月25日00:00:00+0000 | 60| |108 | 2013年2月26日00:00:00+0000 | 2013年2月26日00:00:00+0000 | 2013年2月28日00:00:00+0000 | 60| |108 | 2013年3月1日00:00:00+0000 | 2013年3月1日00:00:00+0000 | 2013年3月14日00:00:00+0000 | 60| |2013年3月15日08:00:00+0000 | 2013年3月15日00:00:00+0000 | 2013年3月25日00:00:00+0000 | 60|

您的错误是由于语句达到默认递归限制100而导致的。这可以通过使用更改。要使用未声明限制的提示,您的语句如下所示:

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

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

如果没有以前的
到期日期怎么办
?总是有一个日期列表。就像我说的,我们每次都会把StartDate作为第一个日期传入。有没有尝试过什么?在这个时间点上没有,这只是我开始写的一个新查询,我会生成一个带有行号的CTE,并使用上一行和下一行,使用
DATEADD
填充
,这段代码很好,谢谢,但在我的数据库上运行时,我无法得到相同的结果。也许他们还需要在窗口中进行分区:<代码>结束(按项目划分无订单依据…