Merge continuous rows with Postgresql

前端 未结 2 1484
没有蜡笔的小新
没有蜡笔的小新 2021-02-13 18:35

I have a slots table like this :

   Column   |            Type             |
------------+-----------------------------+
 id         | integer               


        
2条回答
  •  无人及你
    2021-02-13 19:15

    Gordon Linoff already provided the answer (I upvoted).

    I've used the same approach, but wanted to deal with tsrange type. So I came up with this construct:

    SELECT min(id) b_id, min(begin_at) b_at, max(end_at) e_at, grp, user_id
      FROM (
        SELECT t.*, sum(g) OVER (ORDER BY id) grp
          FROM (
            SELECT s.*, (NOT r -|- lag(r,1,r)
                         OVER (PARTITION BY user_id ORDER BY id))::int g
              FROM (SELECT id,begin_at,end_at,user_id,
                           tsrange(begin_at,end_at,'[)') r FROM slots) s
          ) t
      ) u
     GROUP BY grp, user_id
     ORDER BY grp;
    

    Unfortunately, on the top level one has to use min(begin_at) and max(end_at), as there're no aggregate functions for the range-based union operator +.

    I create ranges with exclusive upper bounds, this allows me to use “is adjacent to” (-|-) operator. I compare current tsrange with the one on the previous row, defaulting to the current one in case there's no previous. Then I negate the comparison and cast to integer, which gives me 1 in cases when new group starts.

提交回复
热议问题