Question

A table with 2 columns ordered by group, number:

group_id | number 
---------+--------
   1     |  101
   1     |  102
   1     |  103
   1     |  106
   2     |  104
   2     |  105
   2     |  107

What SQL query should I write to get the following output:

group_id | number_from | number_to  | total 
---------+-------------+------------+-------
   1     |     101     |    103     |   3
   1     |     106     |    106     |   1
   2     |     104     |    105     |   2
   2     |     107     |    107     |   1
Was it helpful?

Solution

Here is SQL Fiddel Demo

Below is the script

create table Temp(A int,B int);

insert into temp values (1,101);
insert into temp values (1,102);
insert into temp values (1,103);
insert into temp values (1,106);
insert into temp values (2,104);
insert into temp values (2,105);
insert into temp values (2,107);


Select T2.A "group_id",
        Min(T2.B) "number_from",
        Max(T2.B) "number_to",
        Max(T2.E) "total"
from
(
  select *,(B-C) D,
      rank() over 
      (PARTITION by T.A,(B-C) order by T.A,T.B) E,
      rank() over
      (order by T.A,(B-C)) F
  from
  (select A,B,row_number() 
         over (order by (select 0)) C 
   from temp) T
) T2
group by T2.A,T2.D,T2.F
order by 1,2

OTHER TIPS

i used this as example table:

create table temp (id int, val int)
insert into temp values (1,101),(1,102),(2,102),(2,104),(2,107)
insert into temp values (2,103)
insert into temp values (2,105)
insert into temp values (2,108)
insert into temp values (2,110)

this is what you want:

select t1id,cnt, min(t1val) as min, max(t1val), count(t1val) 
from (
    select tt1.*, 
    (select count (*) from 
        (
            select t1.id as t1id,
            t1.val as t1val,
            (select val from temp t2 where t1.id = t2.id and t2.val = t1.val+1 ) as t2val,
            row_number() over (order by t1.id, t1.val ) as rn
            from temp t1
        ) tt2
        where tt2.t2val is null and tt2.rn < tt1.rn
    ) cnt
    from (
        select t1.id as t1id,
        t1.val as t1val,
        (select val from temp t2 where t1.id = t2.id and t2.val = t1.val+1 ) as t2val,
        row_number() over (order by t1.id, t1.val ) as rn
        from temp t1
    ) tt1
)ttt1
group by t1id, cnt
order by t1id, min

update: fixed bug if table is unsorted)

WITH RECURSIVE rope AS (
    SELECT i1.id AS low
     , i1.id AS high
     , i1.grp AS grp
     , 1::integer AS cnt
    FROM islands i1
            -- no left neighbor
    WHERE NOT EXISTS ( SELECT * FROM islands x WHERE x.grp = i1.grp AND x.id = i1.id-1)
    UNION ALL
    SELECT ch.low AS low
     , i2.id AS high
     , i2.grp AS grp
     , 1+ch.cnt AS cnt
    FROM islands i2
            -- connect to left neighbor
    JOIN rope ch ON i2.grp = ch.grp AND i2.id = ch.high+1
    )
SELECT * FROM rope r
    -- suppress subchains
WHERE NOT EXISTS (
    SELECT * FROM rope nx
    WHERE nx.low = r.low AND nx.cnt > r.cnt
    )
    ;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top