【问题标题】:PostgreSQL: Filter select query by comparing against other rowsPostgreSQL:通过与其他行比较来过滤选择查询
【发布时间】:2020-11-12 02:22:18
【问题描述】:

假设我有一个事件表,其中列出了事件发生的 userIdtime

+----+--------+----------------------------+
| id | userId |            time            |
+----+--------+----------------------------+
|  1 |     46 | 2020-07-22 11:22:55.307+00 |
|  2 |    190 | 2020-07-13 20:57:07.138+00 |
|  3 |     17 | 2020-07-11 11:33:21.919+00 |
|  4 |     46 | 2020-07-22 10:17:11.104+00 |
|  5 |     97 | 2020-07-13 20:57:07.138+00 |
|  6 |     17 | 2020-07-04 11:33:21.919+00 |
|  6 |     17 | 2020-07-11 09:23:21.919+00 |
+----+--------+----------------------------+

我想获取同一用户在同一天有前一个事件的事件列表。上表的结果是:

+----+--------+----------------------------+
| id | userId |            time            |
+----+--------+----------------------------+
|  1 |     46 | 2020-07-22 11:22:55.307+00 |
|  3 |     17 | 2020-07-11 11:33:21.919+00 |
+----+--------+----------------------------+

如何执行选择查询,通过根据表中的其他行评估结果来过滤结果?

【问题讨论】:

    标签: sql postgresql select filter


    【解决方案1】:

    这可以使用 EXISTS 条件来完成:

    select t1.*
    from the_table t1
    where exists (select *  
                  from the_table t2
                  where t2.userid = t1.userid -- for the same user
                    and t2.time::date = t1.time::date -- on the same
                    and t2.time < t1.time); -- but previously on that day
    

    【讨论】:

    • 将其标记为正确,因为它是最简洁且易于理解/适应的。我无法评论现阶段的表现。
    【解决方案2】:

    你可以使用lag():

    select t.*
    from (select t.*,
                 lag(time) over (partition by userid, time::date order by time) as prev_time
          from t
         ) t
    where prev_time is not null;
    

    Here 是一个 dbfiddle。

    row_number():

    select t.*
    from (select t.*,
                 row_number() over (partition by userid, time::date order by time) as seqnum
          from t
         ) t
    where seqnum >= 2;
    

    【讨论】:

      【解决方案3】:

      您可以使用LAG() 查找用户的上一行。然后一个简单的比较就会知道它是否发生在同一天。

      例如:

      select *
      from (
        select
          *,
          lag(time) over(partition by userId order by time) as prev_time
        from t
      ) x
      where date::date = prev_time::date
      

      【讨论】:

        【解决方案4】:

        你可以使用ROW_NUMBER()解析函数:

        SELECT id , userId , time
          FROM
          (
           SELECT ROW_NUMBER() OVER (PARTITION BY UserId, date_trunc('day',time) ORDER BY time DESC) AS rn,
                  t.*
             FROM Events
           ) q
         WHERE rn > 1 
        

        为了给在多个事件中发生的 UserId 带来最新的事件。

        【讨论】:

          猜你喜欢
          • 2019-10-17
          • 1970-01-01
          • 1970-01-01
          • 2015-02-05
          • 1970-01-01
          • 2018-03-18
          • 1970-01-01
          • 2018-12-31
          • 1970-01-01
          相关资源
          最近更新 更多