【问题标题】:PostgreSQL select statement to return rows after where conditionPostgreSQL 选择语句在 where 条件之后返回行
【发布时间】:2021-12-31 01:29:51
【问题描述】:

我正在处理一个查询,以在每次发生由“where event = 1”指示的事件时返回接下来 7 天的数据。目标是按用户 ID 对所有数据进行分组,并在事件发生后对这些数据执行聚合函数 - 事件被编码为二进制 [0, 1]。

到目前为止,我一直在尝试使用嵌套的 select 语句来构造我想要的数据,但是使用窗口函数开始限制我。我现在认为自联接可能更合适,但在构建这样的查询时需要帮助。

查询当前首先创建按用户和日期分组的每日聚合值(第 3 级嵌套选择)。然后,第 2 级将数据“value_x”相加得到用户分组的聚合值。然后,第一级嵌套SELECT语句使用引线函数来抓取下一个行值,并由每个用户划分,每个用户划分,当event = 1.最后时,每个用户都在选择下一天的值时,SELECT语句使用聚合函数来计算平均值"sum_next_day_value_after_event" 按用户分组,其中 event = 1。放在一起,其中 event = 1,查询返回下一行总 value_x 的 avg(value_x)。

但是,这不符合我的时间规则; "where event = 1",返回事件发生后接下来 7 天的数据。如果没有 7 天的数据,则返回

这是我到目前为止的以下查询:

select 
    f.user_id
    avg(f.sum_next_day_value_after_event) as sum_next_day_values
from (
    select
        bld.user_id,
        lead(bld.value_x, 1) over(partition by bld.user_id order by bld.daily) as sum_next_day_value_after_event
    from (
        select 
            l.user_id, 
            l.daily, 
            sum(l.value_x) as sum_daily_value_x
        from (
            select
                user_id, value_x, date_part('day', day_ts) as daily
            from table_1
            group by date_part('day', day_ts), user_id, value_x) l
        group by l.user_id, l.day_ts
        order by l.user_id) bld) f
group by f.user_id

下面是 table_1 数据的 sn-p:

user_id day_ts value_x event
50 4/2/21 07:37 25 0
50 4/2/21 07:42 45 0
50 4/2/21 09:14 67 1
50 4/5/21 10:09 8 0
50 4/5/21 10:24 75 0
50 4/8/21 11:08 34 0
50 4/15/21 13:09 32 1
50 4/16/21 14:23 12 0
50 4/29/21 14:34 90 0
55 4/4/21 15:31 12 0
55 4/5/21 15:23 34 0
55 4/17/21 18:58 32 1
55 4/17/21 19:00 66 1
55 4/18/21 19:57 54 0
55 4/23/21 20:02 34 0
55 4/29/21 20:39 57 0
55 4/30/21 21:46 43 0

技术细节:

PostgreSQL,EDB 支持,版本 = 14.1

pgAdmin4,版本 5.7

感谢您的帮助!

【问题讨论】:

标签: postgresql where-clause window-functions self-join


【解决方案1】:

“查询当前首先创建每日聚合值”

我在您的第一个查询中没有看到任何聚合函数,因此GROUP BY 子句没有用。

select
    user_id, value_x, date_part('day', day_ts) as daily
from table_1
group by date_part('day', day_ts), user_id, value_x

可以简化为

select
    user_id, value_x, date_part('day', day_ts) as daily
from table_1

这又没有提供真正的附加值,因此可以删除第一个查询,第二个查询将变为:

select user_id
     , date_part('day', day_ts) as daily
     , sum(value_x) as sum_daily_value_x
 from table_1
group by user_id, date_part('day', day_ts)

order by user_id 子句也可以在此步骤中删除。

现在如果你想计算事件发生后7天内sum_daily_value_x的平均值(我指的是你顶部查询中的avg()函数),你可以使用avg() 作为窗口函数,您可以将其限制在事件发生后的 7 天:

select f.user_id
     , avg(f.sum_daily_value_x) over (order by f.daily range between current row and '7 days' following) as sum_next_day_values
  from (
        select user_id
             , date_part('day', day_ts) as daily
             , sum(value_x) as sum_daily_value_x
          from table_1
         group by user_id, date_part('day', day_ts)
       ) AS f
 group by f.user_id

窗口函数中的partition by f.user_id子句没有用,因为在应用窗口函数之前,行已经按f.user_id分组了。

您可以将avg() 窗口函数替换为任何其他窗口函数,例如sum(),它更适合别名sum_next_day_values

【讨论】:

  • 感谢 cmets 和 range between. . .following 的添加。这部分帮助解决了这个问题。 @Edouard H.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-06
  • 1970-01-01
  • 1970-01-01
  • 2014-09-17
相关资源
最近更新 更多