Что-то вроде этого (предполагается, что таблица называется your_table
и столбец дата названа the_date
) :
with date_range as (
select min(the_date) as oldest,
max(the_date) as recent,
max(the_date) - min(the_date) as total_days
from your_table
),
all_dates as (
select oldest + level - 1 as a_date
from date_range
connect by level <= (select total_days from date_range)
)
select ad.a_date
from all_dates ad
left join your_table yt on ad.a_date = yt.the_date
where yt.the_date is null
order by ad.a_date;
Edit:
Предложение WITH
называется «общим табличным выражением» и эквивалентно производной таблице («встроенный вид»).
Это похоже на
select *
from (
.....
) all_dates
join your_table ...
Второй КТР просто создает список дат «на лету», используя недокументированную особенность connect by
реализации Oracle.
Повторное использование select (как и при вычислении первой и последней даты) немного проще (и IMHO более читаемо), чем с использованием производных таблиц.
Edit 2:
Это может быть сделано с помощью рекурсивного CTE, а также:
with date_range as (
select min(the_date) as oldest,
max(the_date) as recent,
max(the_date) - min(the_date) as total_days
from your_table
),
all_dates (a_date, lvl) as (
select oldest as a_date, 1 as lvl
from date_range
union all
select (select oldest from date_range) + lvl, lvl + 1
from all_dates
where lvl < (select total_days from date_range)
)
select ad.a_date, lvl
from all_dates ad
left join your_table yt on ad.a_date = yt.the_date
where yt.the_date is null
order by ad.a_date;
Который должен работать во всех СУБД, поддерживающих рекурсивный КТР (PostgreSQL и Firebird - быть более совместим со стандартом - действительно нужно ключевое слово recursive
).
Обратите внимание на хак select (select oldest from date_range) + lvl, lvl + 1
в рекурсивной части. Это не обязательно, но у Oracle все еще есть некоторые ошибки в отношении DATE в рекурсивном CTE. В PostgreSQL следующие работы без проблем:
....
all_dates (a_date, lvl) as (
select oldest as a_date, 0 as lvl
from date_range
union all
select a_date + 1, lvl + 1
from all_dates
where lvl < (select total_days from date_range)
)
....
Я думаю, вам придется использовать курсор, чтобы сделать это (в сочетании с SQL, что группы по дате). – theglauber
Нужно ли быть одним запросом или может быть серией инструкций pl/sql? –
Я бы предпочел один запрос, но это может быть сценарий, если это возможно. –