查找最近的逾期之日起

问题描述 投票:3回答:2

我有以下问题:从支付表和会费,我需要找到的最后一个过期的日期。下面是例如表和数据:

create table t (
    Id int
  , [date] date
  , Customer varchar(6)
  , Deal varchar(6)
  , Currency varchar(3)
  , [Sum] int
);

insert into t values
  (1, '2017-12-12', '1110', '111111', 'USD', 12000)
, (2, '2017-12-25', '1110', '111111', 'USD', 5000)
, (3, '2017-12-13', '1110', '122222', 'USD', 10000)
, (4, '2018-01-13', '1110', '111111', 'USD', -10100)
, (5, '2017-11-20', '2200', '222221', 'USD', 25000)
, (6, '2017-12-20', '2200', '222221', 'USD', 20000)
, (7, '2017-12-31', '2201', '222221', 'USD', -10000)
, (8, '2017-12-29', '1110', '122222', 'USD', -10000)
, (9, '2017-11-28', '2201', '222221', 'USD', -30000);

如果“总和”的值是正的 - 这意味着逾期已经开始;如果“总和”是否定的 - 这意味着有人对这笔交易支付。

在2017年12月13日的关于交易“122222”逾期开始上述例子和对2017年12月29日结束,因此它不应该是在结果中。

而对于新政“222221”第一逾期的25000开始于2017年11月20日被完全地支付在2017年11月28日,这样的最后日期当前逾期(我们感兴趣的)是2017年12月31日

我做了这个选择,总结了所有的款项,并坚持在这里:(

WITH cte AS (
    SELECT *,
            SUM([Sum]) OVER(PARTITION BY Deal ORDER BY [Date]) AS Debt_balance
    FROM t
)

显然,我需要找到(每笔交易)最小日期的,如果没有0或负Debt_balance最后余额为0,否则之后的下一个日期..

将是对这个问题的任何提示和建议表示感谢。谢谢!

更新我的解决方案版本:

WITH cte AS (
    SELECT ROW_NUMBER() OVER (ORDER BY Deal, [Date]) id,
           Deal, [Date], [Sum], 
           SUM([Sum]) OVER(PARTITION BY Deal ORDER BY [Date]) AS Debt_balance
    FROM t
)
SELECT  a.Deal, 
        SUM(a.Sum) AS NET_Debt, 
        isnull(max(b.date), min(a.date)), 
        datediff(day, isnull(max(b.date), min(a.date)), getdate())
FROM cte as a 
LEFT OUTER JOIN cte AS b
ON a.Deal = b.Deal AND a.Debt_balance <= 0 AND b.Id=a.Id+1
GROUP BY a.Deal
HAVING SUM(a.Sum) > 0
sql sql-server tsql sql-server-2014
2个回答
1
投票

我相信你要使用运行总和和跟踪,当它变正,而且可以更改为正多次,你想它成为积极的最后日期。您需要LAG()除了运行总和:

WITH cte1 AS (
    -- running balance column
    SELECT *
         , SUM([Sum]) OVER (PARTITION BY Deal ORDER BY [Date], Id) AS RunningBalance
    FROM t
), cte2 AS (
    -- overdue begun column - set whenever running balance changes from l.t.e. zero to g.t. zero
    SELECT *
         , CASE WHEN LAG(RunningBalance, 1, 0) OVER (PARTITION BY Deal ORDER BY [Date], Id) <= 0 AND RunningBalance > 0 THEN 1 END AS OverdueBegun
    FROM cte1
)
-- eliminate groups that are paid i.e. sum = 0
SELECT Deal, MAX(CASE WHEN OverdueBegun = 1 THEN [Date] END) AS RecentOverdueDate
FROM cte2
GROUP BY Deal
HAVING SUM([Sum]) <> 0

Demo on db<>fiddle


1
投票

您可以使用窗口函数。这些可以计算中间值:

  • 最后一天的总和为负(即最后一个“好”的记录)。
  • 最后一笔

然后你就可以将这些:

select deal, min(date) as last_overdue_start_date
from (select t.*,
             first_value(sum) over (partition by deal order by date desc) as last_sum,
             max(case when sum < 0 then date end) over (partition by deal order by date) as max_date_neg
      from t
     ) t
where last_sum > 0 and date > max_date_neg
group by deal;

其实,在最后一天的价值是没有必要的。所以这简化为:

select deal, min(date) as last_overdue_start_date
from (select t.*,
             max(case when sum < 0 then date end) over (partition by deal order by date) as max_date_neg
      from t
     ) t
where date > max_date_neg
group by deal;
© www.soinside.com 2019 - 2024. All rights reserved.