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