【问题标题】:How to group by each date with certain condition in postgresql?如何在postgresql中按特定条件按每个日期分组?
【发布时间】:2019-07-03 16:50:06
【问题描述】:

我在 postgresql 中有一张这样的表。每行显示一个客户订阅了我们的产品。例如,客户 1 在 2019 年 7 月 3 日支付了 1 个月的订阅费。

date       product period subscriber_id units
2019-07-03       A 1Month             1     1
2019-07-02       A  1Year             2     1
2019-07-01       B  1Year             1     1
2019-06-30       B 1Month             3     1
2019-06-30       A 1Month             4     1
2019-06-03       B 1Month             4     1
2019-06-03       A 1Month             1     1

我想计算每天有效的不同订阅者总数,结果如下所示

base_date product total_distinct_count 
2019-07-03      A                    3
2019-07-03      B                    3
2019-07-02      A                    3
2019-07-02      B                    3
2019-07-01      A                    2
2019-07-01      B                    3
2019-06-30      A                    2
2019-06-30      B                    1

...

有 3 个不同的客户(1、2、4)在第一行仍然在 2019-07-03 订阅产品 A。 我尝试每天使用

SELECT date, COUNT(DISTINCT(subscribers_id))
-- do some conditions
GROUP BY date, product

我不知道如何根据这种情况进行分组。如果有更好的方法来解决这个问题。我会非常感激!!!

【问题讨论】:

  • 为什么是distinct?如果您正在尝试计算哪些日子带来最多业务的指标,那么用户购买多个订阅是否重要?另外,是的,date(无时间戳)和product 的组是您想要的。
  • 因为我想查看每天有多少不同的有效订阅者
  • 我可以每天监控订阅者的变化
  • 按产品?看起来你有正确的 SQL。
  • 是的,但我不知道怎么做才能得到结果

标签: groupby distinct count postgresql subscription subscriber


【解决方案1】:

如果您使用日期范围,这非常简单。

CREATE TABLE SUBSCRIPTION (
  date date,
  product text,
  period interval,
  subscriber_id int,
  units int
);

INSERT INTO SUBSCRIPTION VALUES 
 ('2019-07-03', 'A' , '1 month', 1, 1),
 ('2019-07-02', 'A', '1 year', 2, 1),
 ('2019-07-01', 'B', '1 year', 1, 1),
 ('2019-06-30', 'B', '1 month', 3, 1),
 ('2019-06-30', 'A', '1 month', 4, 1),
 ('2019-06-03', 'B', '1 month', 4, 1),
 ('2019-06-03', 'A', '1 month', 1, 1);

-- First, get the list of dateranges, from 2019-06-03 to 2019-07-03 (or whatever you want)
WITH dates as (
  SELECT daterange(t::date, (t + interval '1' day)::date, '[)')
  FROM generate_series('2019-06-03'::timestamp without time zone,
                       '2019-07-03', 
                       interval '1' day) as g(t)
)
  SELECT lower(daterange)::date, count(distinct subscriber_id)
  FROM dates
  LEFT JOIN subscription ON daterange <@
                             daterange(subscription.date,
                                       (subscription.date + period)::date)
  GROUP BY daterange
  ;
   lower    | count
------------+-------
 2019-06-03 |     2
 2019-06-04 |     2
 2019-06-05 |     2
 2019-06-06 |     2
 2019-06-07 |     2
 2019-06-08 |     2
 2019-06-09 |     2
 2019-06-10 |     2
 2019-06-11 |     2
 2019-06-12 |     2
 2019-06-13 |     2
 2019-06-14 |     2
 2019-06-15 |     2
 2019-06-16 |     2
 2019-06-17 |     2
 2019-06-18 |     2
 2019-06-19 |     2
 2019-06-20 |     2
 2019-06-21 |     2
 2019-06-22 |     2
 2019-06-23 |     2
 2019-06-24 |     2
 2019-06-25 |     2
 2019-06-26 |     2
 2019-06-27 |     2
 2019-06-28 |     2
 2019-06-29 |     2
 2019-06-30 |     3
 2019-07-01 |     3
 2019-07-02 |     4
 2019-07-03 |     4
(31 rows)

您可以通过将订阅有效时间存储(和索引)为日期范围而不是在查询中计算它来提高性能。

编辑:正如 Jay 指出的,我忘了按产品分组:

WITH dates as (
  SELECT daterange(t::date, (t + interval '1' day)::date, '[)')
  FROM generate_series('2019-06-03'::timestamp without time zone,
                       '2019-07-03',
                       interval '1' day) as g(t)
)
  SELECT lower(daterange)::date, product, count(distinct subscriber_id)
  FROM dates
  LEFT JOIN subscription ON daterange <@
                             daterange(subscription.date,
                                       (subscription.date + period)::date)
  GROUP BY daterange, product
  ;
   lower    | product | count
------------+---------+-------
 2019-06-03 | A       |     1
 2019-06-03 | B       |     1
 2019-06-04 | A       |     1
 2019-06-04 | B       |     1
 2019-06-05 | A       |     1
 2019-06-05 | B       |     1
 2019-06-06 | A       |     1
 2019-06-06 | B       |     1
 2019-06-07 | A       |     1
 2019-06-07 | B       |     1
 2019-06-08 | A       |     1
 2019-06-08 | B       |     1
 2019-06-09 | A       |     1
 2019-06-09 | B       |     1
 2019-06-10 | A       |     1
 2019-06-10 | B       |     1
 2019-06-11 | A       |     1
 2019-06-11 | B       |     1
 2019-06-12 | A       |     1
 2019-06-12 | B       |     1
 2019-06-13 | A       |     1
 2019-06-13 | B       |     1
 2019-06-14 | A       |     1
 2019-06-14 | B       |     1
 2019-06-15 | A       |     1
 2019-06-15 | B       |     1
 2019-06-16 | A       |     1
 2019-06-16 | B       |     1
 2019-06-17 | A       |     1
 2019-06-17 | B       |     1
 2019-06-18 | A       |     1
 2019-06-18 | B       |     1
 2019-06-19 | A       |     1
 2019-06-19 | B       |     1
 2019-06-20 | A       |     1
 2019-06-20 | B       |     1
 2019-06-21 | A       |     1
 2019-06-21 | B       |     1
 2019-06-22 | A       |     1
 2019-06-22 | B       |     1
 2019-06-23 | A       |     1
 2019-06-23 | B       |     1
 2019-06-24 | A       |     1
 2019-06-24 | B       |     1
 2019-06-25 | A       |     1
 2019-06-25 | B       |     1
 2019-06-26 | A       |     1
 2019-06-26 | B       |     1
 2019-06-27 | A       |     1
 2019-06-27 | B       |     1
 2019-06-28 | A       |     1
 2019-06-28 | B       |     1
 2019-06-29 | A       |     1
 2019-06-29 | B       |     1
 2019-06-30 | A       |     2
 2019-06-30 | B       |     2
 2019-07-01 | A       |     2
 2019-07-01 | B       |     3
 2019-07-02 | A       |     3
 2019-07-02 | B       |     3
 2019-07-03 | A       |     3
 2019-07-03 | B       |     2

【讨论】:

  • 这是不正确的。他想要它“通过”产品。您在产品上缺少分组依据。
猜你喜欢
  • 2022-01-08
  • 2023-03-10
  • 2021-10-30
  • 1970-01-01
  • 2023-03-18
  • 2020-07-25
  • 1970-01-01
  • 2018-06-26
  • 2021-03-05
相关资源
最近更新 更多