#sql #oracle #gaps-and-islands
#sql #Oracle #пробелы и острова
Вопрос:
Я знаю, что вопрос, вероятно, плохо объяснен, но я не знаю, как еще это объяснить. У меня есть следующие данные: (упорядоченные по дате)
DATE GROUP
11-Oct-16 A
12-Oct-16 A
13-Oct-16 A
14-Oct-16 B
15-Oct-16 B
16-Oct-16 A
17-Oct-16 A
18-Oct-16 C
19-Oct-16 C
20-Oct-16 C
21-Oct-16 C
22-Oct-16 A
23-Oct-16 A
24-Oct-16 A
Я хочу найти последовательное использование для групп. Результаты, которые я хочу, объяснят это лучше, чем я:
GROUP MIN(DATE) MAX(DATE)
A 11-Oct-16 13-Oct-16
B 14-Oct-16 15-Oct-16
A 16-Oct-16 17-Oct-16
C 18-Oct-16 21-Oct-16
A 22-Oct-16 24-Oct-16
Есть идеи, как это сделать в oracle sql?
Спасибо.
Комментарии:
1. У вас есть столбец id, который диктует порядок?
Ответ №1:
Это может быть способ:
with test("DATE","GROUP") as
(
select to_date('11-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('12-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('13-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('14-10-16', 'dd-mm-rr'),'B' from dual union all
select to_date('15-10-16', 'dd-mm-rr'),'B' from dual union all
select to_date('16-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('17-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('18-10-16', 'dd-mm-rr'),'C' from dual union all
select to_date('19-10-16', 'dd-mm-rr'),'C' from dual union all
select to_date('20-10-16', 'dd-mm-rr'),'C' from dual union all
select to_date('21-10-16', 'dd-mm-rr'),'C' from dual union all
select to_date('22-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('23-10-16', 'dd-mm-rr'),'A' from dual union all
select to_date('24-10-16', 'dd-mm-rr'),'A' from dual
)
select min("DATE"), max("DATE"), "GROUP"
from (
select "DATE",
"DATE" - row_number() over (partition by "GROUP" order by "DATE") as minDate,
"GROUP"
from test
)
group by "GROUP", minDate
order by "GROUP", minDate
Внутренний запрос строит минимальную дату для группы последовательных дат, в то время как внешний просто агрегирует по этой минимальной дате, создавая таким образом строку для каждой группы последовательных дат.
Кроме того, лучше избегать использования зарезервированных слов в качестве имен столбцов.
Комментарии:
1. В этом случае решение работает, поскольку даты являются последовательными. Более общее решение будет использовать
row_number() over (order by date) - row_number() over (partition by group order by date)
. Полезно знать о других подобных проблемах, когда даты могут быть не последовательными.
Ответ №2:
Так что в основном я думаю, что правильный ответ был в комментарии @mathguy. Здесь я просто расширяю и даю правильный полный запрос.
select GROUP_NAME, grp_id, min(date_field) as starting_date, max(date_field) as ending_date
from (
select DATE_FIELD, GROUP_NAME,
row_number() over ( order by date_field) - row_number() over ( partition by group_name order by date_field ) as grp_id
from darber.my_table) innested
group by GROUP_NAME, grp_id
order by min(date_field);
Пожалуйста, обратите внимание: я изменил имя поля, потому что они вызывали конфликты в моей базе данных. В этом решении DATE теперь DATE_FIELD, а GROUP — ИМЯ_ГРУППЫ.
Я обнаружил, что это действительно умное и элегантное решение. Я надеюсь, что это поможет другим.
Ответ №3:
У меня была такая же проблема с несколькими участниками в группе. Если вы столкнулись с той же проблемой, замените GROUP_NAME на «groupMember1, groupMember2, …»