Sql 每月延迟付款的有条件计数,包括重置为零

Sql 每月延迟付款的有条件计数,包括重置为零,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个具有以下结构的表: EOM ID Principal Pay_plan cum_Payments 2019-12-31 AY4525 25000.000000 796.000000 936.000000 2020-01-31 AY4525 25000.000000 1592.000000 936.000000 2020-02-29 AY4525 25000.000000 2388.000000 936.000000

我有一个具有以下结构的表:

   EOM        ID     Principal       Pay_plan  cum_Payments
2019-12-31  AY4525  25000.000000    796.000000  936.000000
2020-01-31  AY4525  25000.000000    1592.000000 936.000000
2020-02-29  AY4525  25000.000000    2388.000000 936.000000
2020-03-31  AY4525  25000.000000    3184.000000 3184.00000
2020-04-30  AY4525  25000.000000    3980.000000 3980.00000
2020-05-31  AY4525  25000.000000    4776.000000 3980.00000
2020-06-30  AY4525  25000.000000    5572.000000 3980.00000
2020-04-30  KD4525  35000.000000    500.000000  500.000000
2020-05-31  KD4525  35000.000000    1000.000000 1000.00000
2020-06-30  KD4525  35000.000000    1500.000000 1000.00000
2020-07-31  KD4525  35000.000000    2000.000000 2500.00000
因此,我有一个累积付款计划和每个月对唯一客户ID的累积付款。现在,我想添加一个列,开始计算客户延迟付款的月份,因此当pay_plan>cum_Payment时:

   EOM        ID     Principal       Pay_plan  cum_Payments  months_Late
2019-12-31  AY4525  25000.000000    796.000000  936.000000       0
2020-01-31  AY4525  25000.000000    1592.000000 936.000000       1
2020-02-29  AY4525  25000.000000    2388.000000 936.000000       2
2020-03-31  AY4525  25000.000000    3184.000000 3184.00000       0
2020-04-30  AY4525  25000.000000    3980.000000 3980.00000       0
2020-05-31  AY4525  25000.000000    4776.000000 3980.00000       1
2020-06-30  AY4525  25000.000000    5572.000000 3980.00000       2
2020-04-30  KD4525  35000.000000    500.000000  500.000000       0
2020-05-31  KD4525  35000.000000    1000.000000 1000.00000       0
2020-06-30  KD4525  35000.000000    1500.000000 1000.00000       1
2020-07-31  KD4525  35000.000000    2000.000000 2500.00000       0

当再次支付计划=累计付款时,必须重置计数器。我已经尝试了很多方法,但没有找到一个解决方案。有人知道如何解决这个问题吗?

如果我理解您的逻辑正确,最后一行的延迟月数值应该是0,如果正确,您可以使用下面的逻辑来实现您的要求-

对于特定ID,Let cum_付款将始终增加或每天相同

以下查询将返回您正在查找的确切结果。的确,对于具有大量数据的表来说,查询有点重,但如果您只使用过一次此查询,则可以接受。如果需要更多的使用,您可以考虑创建一个视图来提高查询执行性能


如果我理解您的逻辑正确,最后一行的延迟月数值应为0,如果正确,您可以使用以下逻辑来实现您的要求-

对于特定ID,Let cum_付款将始终增加或每天相同

以下查询将返回您正在查找的确切结果。的确,对于具有大量数据的表来说,查询有点重,但如果您只使用过一次此查询,则可以接受。如果需要更多的使用,您可以考虑创建一个视图来提高查询执行性能


这是一个缺口和孤岛问题。当累计金额小于计划金额时,孤岛即为。因此,您可以使用累积和来定义孤岛,然后定义行号:

他是一把小提琴

您可以使用以下方法处理第一次付款延迟的情况:

select t.*,
       (case when cum_payments >= pay_plan then 0
             else row_number() over (partition by id, grp order by eom) - 1 +
                  (case when min(eom) over (partition by id) = min(eom) over (partition by id, grp) and
                             first_value(cum_payments) over (partition by id, grp order by eom) < first_value(pay_plan) over (partition by id, grp order by eom)
                        then 1 else 0
                   end)
        end) as months_late
from (select t.*,
             SUM(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
      from t
     ) t

实际上,我把这个逻辑排除在上面了,因为它看起来不雅观。也许有更好的解决办法,但我并不容易想到。这是一个缺口和孤岛问题。当累计金额小于计划金额时,孤岛即为。因此,您可以使用累积和来定义孤岛,然后定义行号:

他是一把小提琴

您可以使用以下方法处理第一次付款延迟的情况:

select t.*,
       (case when cum_payments >= pay_plan then 0
             else row_number() over (partition by id, grp order by eom) - 1 +
                  (case when min(eom) over (partition by id) = min(eom) over (partition by id, grp) and
                             first_value(cum_payments) over (partition by id, grp order by eom) < first_value(pay_plan) over (partition by id, grp order by eom)
                        then 1 else 0
                   end)
        end) as months_late
from (select t.*,
             SUM(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
      from t
     ) t

实际上,我把这个逻辑排除在上面了,因为它看起来不雅观。也许有更好的解决办法,但我并不容易想到。是修改后的dbfiddle。

这就可以了,但是像我这样在一个大表上运行非常繁重。请检查修改后的代码,它给出了准确的输出。是的,它很重,但最好至少有一个选项:这可以完成任务,但在一个大表上运行(如我的情况)非常重。请检查修改后的代码,它给出了精确的输出。是的,它很重,但最好至少有一个选择:。如果有人支付部分款项,会发生什么情况?比如说,如果3/31的行是2000,而不是3184。如果有人支付部分款项,会发生什么情况?比如说,如果3/31的行为2000,而不是3184?只要第一次付款不迟,工程罚款,请参见:只要第一次付款不迟,工程罚款,请参见:
select t.*,
       (case when cum_payments >= pay_plan then 0
             else row_number() over (partition by id, grp order by eom) - 1
        end) as months_late
from (select t.*,
             sum(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
      from t
     ) t;
select t.*,
       (case when cum_payments >= pay_plan then 0
             else row_number() over (partition by id, grp order by eom) - 1 +
                  (case when min(eom) over (partition by id) = min(eom) over (partition by id, grp) and
                             first_value(cum_payments) over (partition by id, grp order by eom) < first_value(pay_plan) over (partition by id, grp order by eom)
                        then 1 else 0
                   end)
        end) as months_late
from (select t.*,
             SUM(case when cum_payments >= pay_plan then 1 else 0 end) over (partition by id order by eom) as grp
      from t
     ) t