извлечение «заклинаний» из наблюдаемых дат в PostgreSQL

#sql #postgresql

#sql #postgresql

Вопрос:

У меня есть такая таблица

 | winner | year |
|--------|------|
| alice  | 1999 |
| bob    | 2000 |
| bob    | 2001 |
| alice  | 2003 |
| alice  | 2005 |
| alice  | 2007 |
  

Я хотел бы вывести неперекрывающиеся заклинания, то есть таблицу, которая выглядит следующим образом.

 | winner | start| end  |
|--------|------|------|
| alice  | 1999 | 1999 |
| bob    | 2000 | 2001 |
| alice  | 2003 | 2007 |
  

В python я бы сделал что-то вроде

 winners = [(1999, 'alice'),
           (2000, 'bob'),
           (2001, 'bob'),
           (2003, 'alice'),
           (2005, 'alice'),
           (2007, 'alice')]
winners.sort()

spells = []
spell = {}
for year, name in winners:
    if spell:
        if name == spell['name']:
            spell['end'] = year
        else:
            spells.append(spell)
            spell = {'name': name, 'start': year, 'end': year}
    else:
        spell = {'name': name, 'start': year, 'end': year}
  

Но я не уверен, как добиться того же результата в SQL.

Ответ №1:

Это проблема пробелов и островов. Самый простой способ — использовать row_number() :

 select name, min(year), max(year)
from (select t.*, row_number() over (partition by name order by year) as seqnum
      from t
     ) t
group by name, year - seqnum