Использовать иерархический запрос:
SELECT start_date + LEVEL - 1
FROM (
SELECT DATE '2012-04-02' + 1 AS start_date,
DATE '2012-04-30' - 1 AS end_date
FROM DUAL
)
CONNECT BY start_date + LEVEL - 1 <= end_date;
или рекурсивное условие подзапроса:
WITH dates ( value ) AS (
SELECT CAST( DATE '2014-04-02' + 1 AS DATE ) FROM DUAL
UNION ALL
SELECT value + 1 FROM dates WHERE value + 1 < DATE '2014-04-30'
)
SELECT * FROM dates;
или, если вы делаете это в течение всего месяца, кроме этих дат:
WITH boundaries ( start_date, end_date ) AS (
SELECT DATE '2014-04-02', DATE '2014-04-30' FROM DUAL
)
SELECT TRUNC( start_date, 'MM' ) + LEVEL - 1
FROM boundaries
WHERE TRUNC( start_date, 'MM' ) + LEVEL - 1 NOT IN ( start_date, end_date )
CONNECT BY TRUNC( start_date, 'MM' ) + LEVEL - 1 <= LAST_DAY( end_date );
или
WITH boundaries ( start_date, end_date ) AS (
SELECT DATE '2014-04-02', DATE '2014-04-30' FROM DUAL
),
dates ( value ) AS (
SELECT TRUNC( start_date, 'MM' ) FROM boundaries
UNION ALL
SELECT value + 1 FROM dates WHERE value + 1 <= LAST_DAY( value )
)
SELECT *
FROM dates d
WHERE NOT EXISTS ( SELECT 1 FROM boundaries WHERE d.value IN ( start_date, end_date ) );