计算并求和具有最小值的连续记录
Count and Sum consecutive records with minimum value
我有一个 table 显示按月汇总的客户付款。它看起来像这样:
Client | Month1 | Month2 | Month3 | Month4 | Month5 | Month6
------------------------------------------------------------
x1 | 100 | 200 | NULL | 100 | 100 | 100
x2 | 100 | 200 | NULL | NULL | 100 | 100
x3 | NULL | NULL | 200 | 100 | 100 | 100
x4 | NULL | 200 | 300 | 100 | 100 | NULL
x5 | 100 | 200 | 200 | 100 | 100 | 100
x6 | NULL | NULL | NULL | 100 | 100 | 100
x7 | NULL | 200 | 300 | 100 | 100 | 100
x8 | NULL | 200 | NULL | 100 | 100 | NULL
我需要汇总连续付款的值,其中连续付款的次数为>=3
,间隔从上个月开始倒推。
所以应该总结所有有第 6、5 和 4 个月的人以及那些连续付款延伸到过去的人。考虑到这一点,从上面的例子来看,客户 1、3、5、6 和 7 应该在里面,对他们来说,总和应该是:
X1 - Last 3 months
X3 - Last 4 months
X5 - Last 6 months
X6 - Last 3 Months
X7 - Last 5 months
所以从最后一个月到过去的所有月份,其中连续的是 >=3
,直到第一次休息(没有付款的月份)。
也许有一些奇特的方法可以做到,但我目前还没有看到。
我会选择外部应用,因为您想使用计算列两次。
只要达到 null
,case
就会结束。
select *
from data
cross apply (
select cnt = case when month6 is null then 0
when month5 is null then 1
when month4 is null then 2
when month3 is null then 3
when month2 is null then 4
when month1 is null then 5
end
)
where cnt>=3
试试下面的脚本。有点长,大家可以重写一下。
select p1.Client, sum(p1.Amount) Amount
from
(
select Client, MonthName, Amount
from
(
select
Client,
isnull(Month1, 0) Month1,
isnull(Month2, 0) Month2,
isnull(Month3, 0) Month3,
isnull(Month4, 0) Month4,
isnull(Month5, 0) Month5,
isnull(Month6, 0) Month6
from Payment
) pm
unpivot
(
Amount
for MonthName in (Month1, Month2, Month3, Month4, Month5, Month6)
) unpvt
) p1
left join
(
-- get last month with null value
select Client, max(MonthName) MonthName
from
(
select
Client,
isnull(Month1, 0) Month1,
isnull(Month2, 0) Month2,
isnull(Month3, 0) Month3,
isnull(Month4, 0) Month4,
isnull(Month5, 0) Month5,
isnull(Month6, 0) Month6
from Payment
) pm
unpivot
(
Amount
for MonthName in (Month1, Month2, Month3, Month4, Month5, Month6)
) unpvt
where unpvt.Amount = 0
group by unpvt.Client
) p2 on p2.Client = p1.Client and p1.MonthName <= p2.MonthName
where p2.Client is null
group by p1.Client
having count(p1.Client) >= 3
上面的脚本可以通过having子句控制连续月份的计数,比较通用。下面的脚本更具体。
select Client, sumpayment.Amount
from
(
select
Client,
case
when Month6 is null or Month5 is null or Month4 is null then 0
when Month3 is null then Month6 + Month5 + Month4
when Month2 is null then Month6 + Month5 + Month4 + Month3
when Month1 is null then Month6 + Month5 + Month4 + Month3 + Month2
else Month6 + Month5 + Month4 + Month3 + Month2 + Month1
end as Amount
from Payment
) sumpayment
where sumpayment.Amount > 0
阿ツ的回答非常非常好,但是apply
完全没有必要。只需使用子查询或 CTE:
select d.*
from (select d.*,
(case when month6 is null then 0
when month5 is null then 1
when month4 is null then 2
when month3 is null then 3
when month2 is null then 4
when month1 is null then 5
end) as cnt
from data d
) d
where cnt >= 3;
我有一个 table 显示按月汇总的客户付款。它看起来像这样:
Client | Month1 | Month2 | Month3 | Month4 | Month5 | Month6
------------------------------------------------------------
x1 | 100 | 200 | NULL | 100 | 100 | 100
x2 | 100 | 200 | NULL | NULL | 100 | 100
x3 | NULL | NULL | 200 | 100 | 100 | 100
x4 | NULL | 200 | 300 | 100 | 100 | NULL
x5 | 100 | 200 | 200 | 100 | 100 | 100
x6 | NULL | NULL | NULL | 100 | 100 | 100
x7 | NULL | 200 | 300 | 100 | 100 | 100
x8 | NULL | 200 | NULL | 100 | 100 | NULL
我需要汇总连续付款的值,其中连续付款的次数为>=3
,间隔从上个月开始倒推。
所以应该总结所有有第 6、5 和 4 个月的人以及那些连续付款延伸到过去的人。考虑到这一点,从上面的例子来看,客户 1、3、5、6 和 7 应该在里面,对他们来说,总和应该是:
X1 - Last 3 months
X3 - Last 4 months
X5 - Last 6 months
X6 - Last 3 Months
X7 - Last 5 months
所以从最后一个月到过去的所有月份,其中连续的是 >=3
,直到第一次休息(没有付款的月份)。
也许有一些奇特的方法可以做到,但我目前还没有看到。
我会选择外部应用,因为您想使用计算列两次。
只要达到 null
,case
就会结束。
select *
from data
cross apply (
select cnt = case when month6 is null then 0
when month5 is null then 1
when month4 is null then 2
when month3 is null then 3
when month2 is null then 4
when month1 is null then 5
end
)
where cnt>=3
试试下面的脚本。有点长,大家可以重写一下。
select p1.Client, sum(p1.Amount) Amount
from
(
select Client, MonthName, Amount
from
(
select
Client,
isnull(Month1, 0) Month1,
isnull(Month2, 0) Month2,
isnull(Month3, 0) Month3,
isnull(Month4, 0) Month4,
isnull(Month5, 0) Month5,
isnull(Month6, 0) Month6
from Payment
) pm
unpivot
(
Amount
for MonthName in (Month1, Month2, Month3, Month4, Month5, Month6)
) unpvt
) p1
left join
(
-- get last month with null value
select Client, max(MonthName) MonthName
from
(
select
Client,
isnull(Month1, 0) Month1,
isnull(Month2, 0) Month2,
isnull(Month3, 0) Month3,
isnull(Month4, 0) Month4,
isnull(Month5, 0) Month5,
isnull(Month6, 0) Month6
from Payment
) pm
unpivot
(
Amount
for MonthName in (Month1, Month2, Month3, Month4, Month5, Month6)
) unpvt
where unpvt.Amount = 0
group by unpvt.Client
) p2 on p2.Client = p1.Client and p1.MonthName <= p2.MonthName
where p2.Client is null
group by p1.Client
having count(p1.Client) >= 3
上面的脚本可以通过having子句控制连续月份的计数,比较通用。下面的脚本更具体。
select Client, sumpayment.Amount
from
(
select
Client,
case
when Month6 is null or Month5 is null or Month4 is null then 0
when Month3 is null then Month6 + Month5 + Month4
when Month2 is null then Month6 + Month5 + Month4 + Month3
when Month1 is null then Month6 + Month5 + Month4 + Month3 + Month2
else Month6 + Month5 + Month4 + Month3 + Month2 + Month1
end as Amount
from Payment
) sumpayment
where sumpayment.Amount > 0
阿ツ的回答非常非常好,但是apply
完全没有必要。只需使用子查询或 CTE:
select d.*
from (select d.*,
(case when month6 is null then 0
when month5 is null then 1
when month4 is null then 2
when month3 is null then 3
when month2 is null then 4
when month1 is null then 5
end) as cnt
from data d
) d
where cnt >= 3;