SQL Server循环向后遍历结果集

时间:2013-05-22 12:57:36

标签: sql-server-2008

我被赋予了为帐户生成欠款报告的任务。

除了1列,DaysInArrears之外,这是相当直接的。

我创建了一个查询,可以计算每次预定付款时帐户的欠款状态。

此查询使用与以下类似的结果填充临时表(#ArrearsAnalysis):

AgreementID DueDate     AmountDue DueTD  PaidTD FirstPaymentDue ArrearsStatus   RN
184         2013-03-11  75.00     75.00  0.00   2013-03-11      1               1
184         2013-03-25  75.00     150.00 0.00   2013-03-11      1               2
184         2013-04-08  75.00     225.00 300.00 2013-03-11      0               3
184         2013-04-22  75.00     300.00 300.00 2013-03-11      0               4
184         2013-05-03  75.00     375.00 300.00 2013-03-11      1               5
184         2013-05-20  75.00     450.00 300.00 2013-03-11      1               6

我还从以下查询填充了另一个临时表(#ArrearsCheck):

INSERT INTO #ArrearsCheck
SELECT 
    AgreementID, 
    SUM(ArrearsStatus),
    MAX(RN)
FROM 
    #ArrearsAnalysis 
GROUP BY 
    AgreementID

我当时需要做的是在他们陷入最新的欠款(拖欠分数1)时,向后看一行以确定

因此,对于上面的示例,我预计会有03/05/2013的结果。

如果某个帐户从未付款,那么我会返回FirstPaymentDue日期。 如果帐户从未拖欠过,那么我只会返回NULL

以下是我到目前为止处理非付款人和非欠款的问题,我只需要循环处理以解决上述问题(以* *突出显示):

SELECT
    DISTINCT(A.AgreementID),
    CASE WHEN (C.ArrearsTally <= 0) 
    THEN NULL 
    ELSE (CASE WHEN (C.ArrearsTally = C.PaymentCount) 
          THEN NULL 
          *ELSE 0* 
          END) 
    END AS ArrearsDate
FROM
    #ArrearsAnalysis AS A
LEFT OUTER JOIN
    #ArrearsCheck AS C ON A.AgreementID = C.AgreementID

此查询的结果我将传递给下一个查询,该查询将计算今天与结果日期之间的差异(天数)。

1 个答案:

答案 0 :(得分:1)

如果我们可以相信RN(行号?)按顺序编号,那么我们正在查找两个相邻记录,其中最近的记录具有ArrearsStatus = 1且前一个记录具有ArrearsStatus = 0(或者不存在,例如NULL )。我们希望ArrearsStatus = 1记录的日期与最近的此类事件相关联:

SELECT MAX(aa1.DueDate) AS MaxDueDate
FROM #ArrearsAnalysis aa1
LEFT JOIN #ArrearsAnalysis aa2
ON aa2.RN = aa1.RN - 1
WHERE aa1.ArrearsStatus = 1
AND (aa2.ArrearsStatus = 0 OR aa2.ArrearsStatus IS NULL)

如果我们不能信任RN,我们必须从基于日期的连接条件(ON aa2.DueDate&lt; aa1.DueDate)开始,然后找到建立邻接的其他方法。 (可能是中间日期的第三次自联接,然后坚持中间日期为NULL ...)

基于集合的方法通常是比循环更好的方法。在这种情况下,我只会在数据最终使基于集合的方法不切实际时使用游标循环。

您可以添加aa1.AgreementID分组。我认为我们不需要#ArrearsCheck。

更新

上述答案适用于最初被称为“当他们陷入最新欠款时解决”的问题。关于“最早的欠款”的问题实际上更有趣。我们不能只切换到MIN(),因为我们希望只有当CoordinID从一开始就处于拖欠状态时才会看到初始的DueDate,并且从未有过从0过渡到1的时间。

最简单的解决方案是让我找到每种情况的MIN()日期,然后选择这两个值的MAX()。 Nulls应退出总计。

SELECT b.AgreementID,
MAX(b.MinDueDate) AS FirstArrearsDate
FROM (
SELECT aa1.AgreementID,
MIN(aa1.DueDate) AS MinDueDate
FROM #ArrearsAnalysis aa1
LEFT JOIN #ArrearsAnalysis aa2
ON aa2.RN = aa1.RN - 1
WHERE aa1.ArrearsStatus = 1
AND aa2.ArrearsStatus = 0
GROUP BY aa1.AgreementID
UNION ALL
SELECT aa1.AgreementID,
MIN(aa1.DueDate) AS MinDueDate
FROM #ArrearsAnalysis aa1
LEFT JOIN #ArrearsAnalysis aa2
ON aa2.RN = aa1.RN - 1
WHERE aa1.ArrearsStatus = 1
AND aa2.ArrearsStatus IS NULL
GROUP BY aa1.AgreementID
) AS b
GROUP BY b.AgreementID