【问题标题】:How to count occurences in several date ranges in PostgreSQL如何在 PostgreSQL 中计算多个日期范围内的出现次数
【发布时间】:2016-04-28 15:01:16
【问题描述】:

我可以进行查询,以获取每月和每家商店从 18 岁到 24 岁进店的顾客数量。 我是这样做的:

select year, month, shop_id, count(birthday) 
from customers 
where birthday 
BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00'
group by year, month, shop_id;

现在,我在同时对多个范围进行此查询时遇到问题。

我目前有这个数据库架构:

shop_id | birthday | year | month |
--------+----------+------+--------
 567   | 1998-10-10 | 2014 | 10 |
 567   | 1996-10-10 | 2014 | 10 |
 567   | 1985-10-10 | 2014 | 10 |
 234   | 1990-10-10 | 2014 | 10 |
 123   | 1970-01-10 | 2014 | 10 |
 123   | 1974-01-10 | 2014 | 11 |

我想得到这样的东西:

shop_id | year | month | 18 < age < 25 | 26 < age < 35
--------+------+-------+---------------+-------------
567   |  2014  | 10    | 2             | 1
234   |  2014  | 10    | 1             | 0
123   |  2014  | 10    | 0             | 0

在第一个查询中,它不管理一个商店没有客户的情况。没有怎么取0?

如何同时查询多个日期范围?

【问题讨论】:

  • 在选择列表中有 case 表达式,每个年龄段都有一个。例如。 , count(case when ... then 1 end) as 18_age_25, count(case when ....

标签: sql postgresql date count date-range


【解决方案1】:

用用例语句代替过滤器:

select year, month, shop_id, 
count(case when birthday between <range1> then 1 end) RANGE1,
count(case when birthday between <range2> then 1 end) RANGE2,
count(case when birthday between <range3> then 1 end) RANGE3
from customers 
group by year, month, shop_id;

【讨论】:

  • 非常感谢!简单高效。
【解决方案2】:

“没有零行”是GROUP BY 查询的常见问题。解决方案是让您的FROM 成为具有完整列表的任何表,然后执行LEFT JOIN。由于您也按年份和月份分组,因此您需要生成完整的年份和月份列表。你可以通过generate_series 做到这一点:

SELECT  t.t, s.id, COUNT(c.birthday) 
FROM    shops s
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t)
LEFT OUTER JOIN customers c
ON      c.shop_id = s.id
AND     c.birthday 
        BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00'
AND     c.year = EXTRACT(YEAR FROM t.t)
AND     c.month = EXTRACT(MONTH FROM t.t)
GROUP BY t.t, s.id
ORDER BY s.id, t.t;

要获得两个日期范围的计数,您可以按照@mo2 的建议进行操作,或者您可以加入customers 表两次:

SELECT  t.t, s.id, COUNT(DISTINCT c1.id), COUNT(DISTINCT c2.id) 
FROM    shops s
CROSS JOIN generate_series('2014-01-01 00:00:00', '2015-01-01 00:00:00', interval '1 month') t(t)
LEFT OUTER JOIN customers c1
ON      c1.shop_id = s.id
AND     c1.birthday 
        BETWEEN '1992-01-01 00:00:00' AND '1998-01-01 00:00:00'
AND     c1.year = EXTRACT(YEAR FROM t.t)
AND     c1.month = EXTRACT(MONTH FROM t.t)
LEFT OUTER JOIN customers c2
ON      c2.shop_id = s.id
AND     c2.birthday 
        BETWEEN '1982-01-01 00:00:00' AND '1992-01-01 00:00:00'
AND     c2.year = EXTRACT(YEAR FROM t.t)
AND     c2.month = EXTRACT(MONTH FROM t.t)
GROUP BY t.t, s.id
ORDER BY s.id, t.t;

请注意,在这两个查询中,我是 SELECTing 一个完整的日期时间,而不是 yearmonth。我认为这更灵活,但如果你愿意,它应该很容易改变。

编辑:我意识到您的yearmonth 与生日无关,但还有别的,我猜是访问日期?所以我更新了我的查询。如果您一次只检查一个月,您可以删除 generate_series 并将年份和月份整数直接放入连接条件中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-15
    • 2021-11-29
    • 2021-04-11
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 1970-01-01
    相关资源
    最近更新 更多