Меня порадовало что на простые запросы многие быстро дают ответы. Приведеная ниже задача уже решена, но мне интересно, как вы с ней справитесь? Как оцените?
ЗЫ: На сложность задачи не претендую.
И так.
Есть таблица:
work_date | id_work
___________|_________
..........
01.01.2006 | 10
02.01.2006 | 10
........
........ Даты по порядку, причем id_work может быть null, но не меняться......
.......
04.02.2006 | 20
05.02.2006 | 20
.....
..... Тоже самое .....
.....
03.03.2006 | 50
04.03.2006 | 10
05.03.2006 | 10
.....
.....
.....
Т.о. надо найти все периоды по id_work и вывести в виде:
date_beg | date_end | id_work
___________|____________|________
....... | .... | ...
....... | ..... | ...
01.01.2006 | 02.01.2006 | 10
04.02.2006 | 05.02.2006 | 20
03.03.2006 | 03.03.2006 | 50
04.03.2006 | 05.03.2006 | 10
......
......
Здравствуйте, FunnyRabbit, Вы писали:
FR> Приведеная ниже задача уже решена,
Причем неоднократно.
FR>Т.о. надо найти все периоды по id_work и вывести в виде:
Ну, во-первых, эта формулировка не совсем соответствует нарисованному Вами результату. Во-вторых, если отталкиваться от результата, то простейший путь, работающий практически в любой версии Oracle
Здравствуйте, Softwarer, Вы писали:
S>Здравствуйте, FunnyRabbit, Вы писали:
FR>> Приведеная ниже задача уже решена,
S>Причем неоднократно.
Я и не говорил, что она оригинальна и сложна.
FR>>Т.о. надо найти все периоды по id_work и вывести в виде:
S>Ну, во-первых, эта формулировка не совсем соответствует нарисованному Вами результату. Во-вторых, если отталкиваться от результата, то простейший путь, работающий практически в любой версии Oracle
S>
group by id_work, work_date - rownum
Может быть формулировка не верна. Но если отталкиваться от результата, то каким макаром должно работать по вашему:
group by id_work, work_date - rownum
У меня выдает ошибку (Error): ORA-00979: выражение не являеться выражением GROUP BY...
Здравствуйте, Softwarer, Вы писали:
S>Впрочем, если Вы не поняли основной идеи этой группировки, то просто так написать соответствующий запрос действительно не удастся.
Ну так я же просил решения полностью. А в предложеном Вами варианте, ооооочень много вариаций.
create table #work_dates ( work_date datetime,
id_work int
)
insert into #work_dates (work_date, id_work)
select '01.02.2006', 10
union
select '02.02.2006', 10
union
select '03.02.2006', 50
union
select '04.02.2006', 20
union
select '05.02.2006', 20
union
select '06.02.2006', 10
union
select '07.02.2006', 10
union
select '08.02.2006', 20
union
select '09.02.2006', 20
select *
from #work_dates
select innerSelect.work_date,
case
when innerSelect.id_next_for_single is null and id_next <> id_work then innerSelect.work_date
else innerSelect.date_end
end,
innerSelect.id_work
from (
select work_date, id_work,
( select top 1 work_date
from #work_dates WDTemp
where WDTemp.work_date > WD.work_date
) date_end,
( select top 1 id_work
from #work_dates WDTemp
where WDTemp.work_date > WD.work_date
) id_next,
( select top 1 WDTemp.id_work
from #work_dates WDTemp
where WDTemp.work_date < WD.work_date and WDTemp.id_work = WD.id_work
) id_next_for_single
from #work_dates WD
) innerSelect
where id_next = id_work or id_next_for_single is null
drop table #work_dates
Здравствуйте, FunnyRabbit, Вы писали:
FR>Спасибо. Вариаций действительно много, хоть вы их и не видите.
Вариаций на тему указанного мной метода группировки. Ту же идею можно выразить через аналитические функции, но это будет менее удачно — поскольку результат потом все равно надо будет сжимать group by-ем. Вариации с другой исходной посылкой, разумеется, есть.
Здравствуйте, Softwarer, Вы писали:
S>Здравствуйте, FunnyRabbit, Вы писали:
FR>>Спасибо. Вариаций действительно много, хоть вы их и не видите.
S>Вариаций на тему указанного мной метода группировки. Ту же идею можно выразить через аналитические функции, но это будет менее удачно — поскольку результат потом все равно надо будет сжимать group by-ем. Вариации с другой исходной посылкой, разумеется, есть.
Согласен, что все сводиться в конечном итоге к группировке. Спасибо за урок. Надеюсь что не последний.
declare @dm table( dt datetime, id int )
insert @dm values('2006-01-01', 10)
insert @dm values('2006-01-02', 10)
insert @dm values('2006-02-04', 20)
insert @dm values('2006-02-05', 20)
insert @dm values('2006-02-06', null)
insert @dm values('2006-03-03', 50)
insert @dm values('2006-03-04', 10)
insert @dm values('2006-03-05', 10)
insert @dm values('2006-03-06', 10)
select a.dt,min(b.dt),a.id from @dm a join @dm b on
a.dt <= b.dt and not exists(
select * from @dm c where ( c.dt=b.dt+1 and isnull(c.id,0)=isnull(b.id,0))
or (c.dt=a.dt-1 and isnull(c.id,0)=isnull(a.id,0))
)
group by a.dt, a.id
order by 1,2
H>declare @dm table( dt datetime, id int )
H>select a.dt,min(b.dt),a.id from @dm a join @dm b on
H>a.dt <= b.dt and not exists(
H> select * from @dm c where ( c.dt=b.dt+1 and isnull(c.id,0)=isnull(b.id,0))
H> or (c.dt=a.dt-1 and isnull(c.id,0)=isnull(a.id,0))
H>)
H>group by a.dt, a.id
H>order by 1,2
H>
Поднимаю старый вопрос, так как нужна помощь.
При таких данных
Здравствуйте, Holms, Вы писали:
H>результат не правильный, т.е. ничего после 2006-09-11 не выводится H>Any ideas?
А самому разобраться? Ошибка же очевидная...
select a.dt,min(b.dt),a.id from @dm a join @dm b on
a.dt <= b.dt anda.id=b.id and not exists(
select * from @dm c where ( c.dt=b.dt+1 and c.id=b.id )
or (c.dt=a.dt-1 and c.id=a.id)
)
group by a.dt, a.id
order by 1,2
Здравствуйте, FunnyRabbit, Вы писали:
S>>Вариаций на тему указанного мной метода группировки. Ту же идею можно выразить через аналитические функции, но это будет менее удачно — поскольку результат потом все равно надо будет сжимать group by-ем. Вариации с другой исходной посылкой, разумеется, есть.
FR>Согласен, что все сводиться в конечном итоге к группировке. Спасибо за урок. Надеюсь что не последний.
Можно и без группировок.
SQL> create table work_data as
2 (
3 select to_date ( '01.01.2006', 'dd.mm.yyyy' ) work_date, 10 id_work from dual union all
4 select to_date ( '02.01.2006', 'dd.mm.yyyy' ) work_date, 10 id_work from dual union all
5 select to_date ( '03.02.2006', 'dd.mm.yyyy' ) work_date, 20 id_work from dual union all
6 select to_date ( '04.02.2006', 'dd.mm.yyyy' ) work_date, 20 id_work from dual union all
7 select to_date ( '05.02.2006', 'dd.mm.yyyy' ) work_date, 20 id_work from dual union all
8 select to_date ( '03.03.2006', 'dd.mm.yyyy' ) work_date, 50 id_work from dual union all
9 select to_date ( '04.03.2006', 'dd.mm.yyyy' ) work_date, 10 id_work from dual union all
10 select to_date ( '05.03.2006', 'dd.mm.yyyy' ) work_date, 10 id_work from dual
11 );
Table created.
SQL>
SQL> select date_beg, date_end, id_work
2 from (select wrn, id_work,
3 work_date date_beg,
4 lead(work_date, 1, work_date) over(partition by id_work order by id_work, work_date) date_end,
5 row_number() over(partition by id_work order by id_work, work_date) irn
6 from (select wd.*, rownum wrn from work_data wd))
7 where mod(irn, 2) = 1
8 order by wrn;
DATE_BEG DATE_END ID_WORK
---------- ---------- ----------
01.01.2006 02.01.2006 10
03.02.2006 04.02.2006 20
05.02.2006 05.02.2006 20
03.03.2006 03.03.2006 50
04.03.2006 05.03.2006 10
SQL>
SQL> drop table work_data;
Table dropped.