将具有相同值的相邻行分组

时间:2020-07-13 18:33:18

标签: sql postgresql select

具有下表: https://www.db-fiddle.com/f/avcRnMG6SVAoRuV5Rf4znF/2

create table tbl
   (id integer,
    start integer,
    stop integer,
    type integer);
    
    INSERT INTO tbl values
    
    (101, 1, 3, 10),
    (101, 3, 6, 15),
    (101, 6, 10, 17),
    (101, 10, 40, 20),
    (101, 40, 100, 20),
    (101, 100, 200, 20),
    (101, 200, 500, 55);

我想用边界值startstop将具有相同值的相邻行分组。因此,结果应该是3行而不是type 20

101, 10, 200, 20

我尝试过类似的方法,但效果远非如此,那里有什么明智的,简短的解决方案吗?

SELECT 
    id, 
   case when lag(type) OVER (partition by id ORDER BY start ) = type 
   then lag(start) OVER (partition by id ORDER BY start) else start end as from
   , case when lead(type) OVER (partition by id ORDER BY start ) = type 
   then lead(stop) OVER (partition by id ORDER BY start) else stop end as to
   , type
   
from tbl

2 个答案:

答案 0 :(得分:1)

可能会有更简洁的方法来执行此操作,但这就是我通常为此类要求解决的方式。您可以取消注释底部的其他选项,以查看每个步骤的作用。

fiddle here

  1. 注释记录type的更改
  2. 使用sum()将行分配给分组,其中type在连续的行中保持不变
  3. 对重复的组使用startstop

with changes as (
  select *, 
         case 
           when lag(type) over (partition by id
                                    order by start) = type then 0
           else 1
         end as changed
    from tbl
), groups as (
  select *,
         sum(changed) over (partition by id
                                order by start) as grp
    from changes
), combined as (
  select id, 
         min(start) as start,
         max(stop) as stop,
         type 
    from groups
   group by id, grp, type
)
--select * from changes order by start;
--select * from groups order by start;
select * from combined order by start;

答案 1 :(得分:1)

display:block值似乎正在稳定增加,因此不再重复。因此,看起来简单的type就足够了:

group by

如果类型可以散布,则需要使用更复杂的查询将其视为“隔岛问题”。

相关问题