Вот способ создания списка дат и их соответствующих значений недели и недели-месяца на основе сказанной вами логики (т. Е. Если последняя дата в неделе является 1-й, 2-й, 3-й или 4-й из месяц, неделя относится к предыдущему месяцу):
WITH week_months AS (SELECT dt,
dt_week_start,
dt_week_end,
to_number(to_char(dt, 'ww')) week_no,
to_number(CASE WHEN TRUNC(dt_week_start, 'mm') != TRUNC(dt_week_end, 'mm') AND to_char(dt_week_end, 'dd') < '05' THEN to_char(dt_week_start, 'mm')
ELSE to_char(dt_week_end, 'mm')
END) mnth
FROM (SELECT to_date('01/01/2018', 'dd/mm/yyyy') -1 + LEVEL dt,
trunc(to_date('01/01/2018', 'dd/mm/yyyy') -1 + LEVEL, 'ww') dt_week_start,
trunc(to_date('01/01/2018', 'dd/mm/yyyy') -1 + LEVEL, 'ww') + 6 dt_week_end
FROM dual
CONNECT BY LEVEL <= 400))
SELECT *
FROM week_months
ORDER BY dt;
Вы можете использовать это динамически (вам нужно изменить внутренний выбор в подзапросе week_months, чтобы выбрать интересующие вас даты; здесь я только что выбрал 400 дней с 1 января 2018 года, но вам может понадобиться минимальные / максимальные даты в вашей таблице), но в зависимости от того, как часто выполняется запрос, вам может быть лучше заполнить таблицу и использовать ее для соединения с другими таблицами.