Единственная очевидная ошибка в размещенном вами коде - это то, что у вас есть form dual
вместо from dual
.Но с этим исправлением это не дает желаемого результата, так как вы получаете только даты и только для одного сотрудника:
THEDATE
----------
2013-01-01
2013-01-02
2013-01-03
2013-01-04
Вы можете удалить фильтр и добавить значение emp_ser
хотя:
with nums as (
SELECT level-1 daystoadd
from dual
connect by level <= 60
)
select from_date + daystoadd thedate, emp_ser
from emp_vac
cross join nums
where emp_vac.to_date - emp_vac.from_date + 1 > daystoadd -- and (emp_ser='5150')
order by emp_ser, thedate;
THEDATE EMP_SER
---------- ----------
2013-01-01 5150
2013-01-02 5150
2013-01-03 5150
2013-01-04 5150
2013-01-05 5151
2013-01-06 5151
Жесткий лимит в 60 дней немного неловкий.Вы можете получить тот же результат с помощью одного иерархического запроса:
select from_date + level - 1 as vac_date, emp_ser
from emp_vac
connect by emp_ser = prior emp_ser
and level <= to_date - from_date + 1
and prior dbms_random.value is not null;
VAC_DATE EMP_SER
---------- ----------
2013-01-01 5150
2013-01-02 5150
2013-01-03 5150
2013-01-04 5150
2013-01-05 5151
2013-01-06 5151
, которому нужен неуклюжий вызов недетерминированной функции (в данном случае dbms_random.value
, но вы можете использовать другие) для правильной работынесколько исходных строк;или с рекурсивным факторингом подзапроса :
with rcte (vac_date, to_date, emp_ser) as (
select from_date, to_date, emp_ser
from emp_vac
union all
select vac_date + 1, to_date, emp_ser
from rcte
where vac_date < to_date
)
select vac_date, emp_ser
from rcte
order by emp_ser, vac_date;
VAC_DATE EMP_SER
---------- ----------
2013-01-01 5150
2013-01-02 5150
2013-01-03 5150
2013-01-04 5150
2013-01-05 5151
2013-01-06 5151
Здесь якорный элемент получает дату начала каждой записи, а рекурсивный элемент добавляет день за один раз, пока он не достигнет даты окончания.(Кстати, я бы посоветовал не использовать имя функции, например to_date
, в качестве имени столбца - это законно, но сбивает с толку.)
Конечно, если период отпуска охватывает выходные или другие выходные, то все этиподходы будут включать те нерабочие дни, которые могут не соответствовать вашим ожиданиям.Исключить выходные было бы относительно просто, но чтобы исключить другие праздники, вам понадобится справочная таблица, в которой указаны эти даты.
Как отметил @PonderStibbons в комментарии, существует ошибка с датами и рекурсивомCTE в некоторых версиях (возможно, только 11.2.0.1 и 11.2.0.2 - похоже, ошибка 11840579, которая показана как исправленная в 11.2.0.3 в MoS);Это обходной путь для Ponder, использующий числа вместо дат для ограничения рекурсивного члена:
with rcte (rn, diff, from_date, emp_ser) as (
select 1, trunc(to_date - from_date), from_date, emp_ser from emp_vac
union all
select rn + 1, diff, from_date, emp_ser from rcte where rn <= diff )
select from_date + rn - 1 vac_date, emp_ser
from rcte
order by emp_ser, vac_date;
... и db <> fiddle (11.2.0.2).