计算满足GROUP BY

时间:2017-04-06 15:49:01

标签: 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
 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

换句话说,如果您在任何时候付款,我想忽略所有之前的条目,并且只计算自您上次付款以来您已经支持的结算周期数。我最简单的做法是什么?

2 个答案:

答案 0 :(得分: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,因此您不需要group by子句。

答案 1 :(得分:0)

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