Postgresql 按顺序计算满足组内条件的连续条目数
我有一个拖欠账单的用户列表,我想为每个用户生成一个条目,说明他们连续拖欠了多少账单。下面是表格:Postgresql 按顺序计算满足组内条件的连续条目数,postgresql,Postgresql,我有一个拖欠账单的用户列表,我想为每个用户生成一个条目,说明他们连续拖欠了多少账单。下面是表格: user | bill_date | outstanding_balance --------------------------------------- a | 2017-03-01 | 90 a | 2016-12-01 | 60 a | 2016-09-01 | 30 b | 2017-03-01 | 50
user | bill_date | outstanding_balance
---------------------------------------
a | 2017-03-01 | 90
a | 2016-12-01 | 60
a | 2016-09-01 | 30
b | 2017-03-01 | 50
b | 2016-12-01 | 0
b | 2016-09-01 | 40
c | 2017-03-01 | 0
c | 2016-12-01 | 0
c | 2016-09-01 | 1
我想要一个生成下表的查询:
user | consecutive_billing_periods_behind
-----------------------------------------
a | 3
b | 1
a | 0
换句话说,如果你在任何时候都已经付清了,我想忽略前面的所有条目,只计算一下自从你上次付清账单以来你已经落后了多少个账单周期。如何最简单地做到这一点?如果我正确理解了这个问题,首先您需要找到任何给定客户支付账单的最后日期,以便其未付余额的最后日期为0。可以通过此子查询执行此操作:
(SELECT
user1,
bill_date AS no_outstanding_bill_date
FROM table1
WHERE outstanding_balance = 0)
然后,您需要获取最后的账单日期,并为每行创建字段(如果它们是未付账单)。然后根据where子句过滤每个客户的最后一个清零日到最后一个账单日期之间的行:
WHERE bill_date >= last_clear_day AND bill_date <= last_bill_date
然后,如果将这些部分放在一起,则可以通过此查询得到结果:
SELECT
DISTINCT
user1,
sum(is_outstanding_bill)
OVER (
PARTITION BY user1 ) AS consecutive_billing_periods_behind
FROM (
SELECT
user1,
last_value(bill_date)
OVER (
PARTITION BY user1
ORDER BY bill_date
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS last_bill_date,
CASE WHEN outstanding_balance > 0
THEN 1
ELSE 0 END AS is_outstanding_bill,
bill_date,
outstanding_balance,
nvl(max(t2.no_outstanding_bill_date)
OVER (
PARTITION BY user1 ), min(bill_date)
OVER (
PARTITION BY user1 )) AS last_clear_day
FROM table1 t1
LEFT JOIN (SELECT
user1,
bill_date AS no_outstanding_bill_date
FROM table1
WHERE outstanding_balance = 0) t2 USING (user1)
) table2
WHERE bill_date >= last_clear_day AND bill_date <= last_bill_date
因为我们使用的是distinct,所以您不需要GROUPBY子句
select
user,
count(case when min_balance > 0 then 1 end)
as consecutive_billing_periods_behind
from
(
select
user,
min(outstanding_balance)
over (partition by user order by bill_date) as min_balance
from tbl
)
group by user
或:
select
user,
count(*)
as consecutive_billing_periods_behind
from
(
select
user,
bill_date,
max(case when outstanding_balance = 0 then bill_date) over
(partition by user)
as max_bill_date_with_zero_balance
from tbl
)
where
-- If user has no outstanding_balance = 0, then
max_bill_date_with_zero_balance is null
-- Count all rows in this case.
-- Otherwise
or
-- count rows with
bill_date > max_bill_date_with_zero_balance
group by user