【问题标题】:Select one row per day for each value每天为每个值选择一行
【发布时间】:2015-06-23 21:17:32
【问题描述】:

我在 PostgreSQL 9.4 中有一个 SQL 查询,虽然由于我从中提取数据的表而更加复杂,但归结为以下几点:

SELECT entry_date, user_id, <other_stuff>
FROM <tables, joins, etc>
GROUP BY entry_date, user_id
WHERE <whatever limits I want, such as limiting the date range or users>

结果是每个用户每天都有一行数据。通常,此查询将在一个月的 entry_date 期间运行,期望的结果是每个用户在一个月中的每一天都有一行。

问题是每个月的每一天都可能没有每个用户的数据,并且此查询仅返回有数据的日期的行。

是否有某种方法可以修改此查询,使其每天为每个用户返回一行,即使某些行中没有数据(日期和用户除外)?

我尝试使用generate_series() 进行连接,但这没有用 - 它可以使没有丢失的日期,但不是每个用户。我真正需要的是“对于列表中的每个用户,生成一系列(user,date) 记录”

编辑:为了澄清,我正在寻找的最终结果是对于数据库中的每个用户 - 定义为用户表中的记录 - 我希望每个日期一行。因此,如果我在 where 子句中指定 5/1/15-5/31/15 的日期范围,我希望每个用户有 31 行,即使该用户在该范围内没有数据,或者只有几个数据天。

【问题讨论】:

  • 所以您只希望结果中的用户在上个月至少有一个条目?或者,请准确定义您想要的内容。

标签: sql postgresql time-series cross-join generate-series


【解决方案1】:

generate_series() 是正确的想法。你可能没有得到正确的细节。可以这样工作:

WITH cte AS (
   SELECT entry_date, user_id, <other_stuff>
   FROM   <tables, joins, etc>
   GROUP  BY entry_date, user_id
   WHERE  <whatever limits I want>
   ) 
SELECT *
FROM  (SELECT DISTINCT user_id FROM cte) u
CROSS  JOIN (
   SELECT entry_date::date 
   FROM   generate_series(current_date - interval '1 month'
                        , current_date - interval '1 day'
                        , interval '1 day') entry_date
   ) d
LEFT   JOIN cte USING (user_id, entry_date);

我选择了一个以“昨天”结束的一个月的运行时间窗口。您没有准确定义您的“月份”。

假设entry_date为数据类型date

更新后的要求更简单

要为users 表中的每个 用户(而不是当前选择)和给定的时间范围获取结果,它会变得更简单。您不需要 CTE:

SELECT *
FROM   (SELECT user_id FROM users) u
CROSS  JOIN (
   SELECT entry_date::date 
   FROM   generate_series(timestamp '2015-05-01'
                        , timestamp '2015-05-31'
                        , interval '1 day') entry_date
   ) d
LEFT   JOIN (
   SELECT entry_date, user_id, <other_stuff>
   FROM   <tables, joins, etc>
   GROUP  BY entry_date, user_id
   WHERE  <whatever>
   ) t USING (user_id, entry_date);

为什么要用这种特殊的方式调用generate_series()

最好使用ISO 8601 date format (YYYY-MM-DD),无论区域设置如何。

【讨论】:

  • 完美!这是我缺少的 CROSS JOIN - 以前从未使用过,只是模糊地意识到它。我没有准确定义我的月份,因为那不是我遇到困难的地方:-) 然而,在我的特定用例中,它通常是一个任意的日历月。
  • @ibrewster:我为您更新的需求添加了一个更简单的查询。最好总是准确定义,以避免误解。
猜你喜欢
  • 2012-01-04
  • 2022-01-18
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 2018-03-04
  • 2020-05-20
  • 1970-01-01
相关资源
最近更新 更多