Мне велено создать календарь, похожий на календарь, на основе существующих записей и указать, существует ли запись на эту дату.
Чтобы получить пример сценария, возьмите эти записи из таблицы образца:TIME_LOG
(ID
, PUNCH_TIME
).
1 1/1/2018 8:00:00
2 1/1/2018 12:12:00
...
n 2/14/2020 8:00:00
В этом примере мне нужно сделать следующее:
- Получить все имеющиеся месяцы на
TIME_LOG
, которые относятся к январю 2018 года и февралю 2020 года. - Перечислите все даты в этих двух месяцах: 1–31 января 2018 года плюс 1–29 февраля 2020 года. Затем укажите его в столбце
DATE_TOKEN
из набора результатов. - Установите
'Record found'
или 'No records found'
, существует ли значение из столбца DATE_TOKEN
из TIME_LOG
.Сделайте это как столбец IS_FOUND
набора результатов.
Чтобы получить этот набор результатов, это мой предварительный запрос:
SELECT a.date_token,
NVL2 (b.date_token, 'Record found.',
'No records found.') AS is_found
FROM (SELECT TO_DATE (a.MONTH || '/' || b.DAY || '/' || a.YEAR,
'MM/DD/YYYY'
) AS date_token
FROM (SELECT TO_CHAR (EXTRACT (MONTH FROM a.punch_time)
) AS MONTH,
TO_CHAR (EXTRACT (YEAR FROM a.punch_time)) AS YEAR
FROM vw_each_punch a
GROUP BY TO_CHAR (EXTRACT (MONTH FROM a.punch_time)),
TO_CHAR (EXTRACT (YEAR FROM a.punch_time))) a
JOIN
(SELECT TO_CHAR (ROWNUM) AS DAY
FROM DUAL
CONNECT BY ROWNUM <= 31) b
-- I placed this condition to eliminate dates such as February 31, etc.
-- and it works unless I uncomment the WHERE clause below.
ON b.DAY <=
EXTRACT (DAY FROM LAST_DAY (TO_DATE ( a.MONTH
|| '/1/'
|| a.YEAR,
'MM/DD/YYYY'
)
)
)
) a
LEFT JOIN
(SELECT TRUNC (a.punch_time) AS date_token
FROM vw_each_punch a
GROUP BY TRUNC (a.punch_time)) b ON b.date_token = a.date_token
-- WHERE TRUNC (a.date_token, 'MONTH') = '1-FEB-2020'
ORDER BY 1, 2
Это работает нормально и возвращает 60 строкнабор результатов, аналогичный этому (DATE_TOKEN
, IS_FOUND
):
1/1/2018 Record found.
1/2/2018 No records found.
1/3/2018 No records found.
...
2/13/2018 No records found.
2/14/2018 Record found.
2/15/2018 No records found.
...
, пока мне не понадобилось фильтровать набор результатов по определенным месяцам.Когда я пытаюсь раскомментировать предложение WHERE
в моем запросе, чтобы показать только даты февраля 2020 года, оно выдает мне ошибку:
ORA-01839: date not valid for month specified
Набор результатов загружается полностью без каких-либо ошибок, если нетWHERE
предложение, показанное предыдущим набором результатов с 60 строками.Я подозреваю, что ошибка происходит из-за того, что февраль 2020 года составляет менее 31 дня, но это было удалено условием b.DAY <= EXTRACT (DAY FROM LAST_DAY (TO_DATE (a.MONTH || '/1/' || a.YEAR, 'MM/DD/YYYY')))
.Кроме того, я изменил условие с февраля 2020 года на январь 2018 года, но оно по-прежнему не работает.
Можно ли как-нибудь использовать предложение WHERE
, не выдавая ошибку ORA-01839
?
Вот пример запущенного SQL с использованием факторинга подзапроса, если вам нужно запустить его как можно скорее:
WITH time_log_temp (id, punch_time)
AS (SELECT 1,
To_date('2018-1-1 8:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual
UNION ALL
SELECT 2,
To_date('2018-1-1 12:12:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual
UNION ALL
SELECT 2,
To_date('2020-2-14 8:00:00 AM', 'YYYY-MM-DD HH:MI:SS AM')
FROM dual),
inter
AS (SELECT a.date_token,
Nvl2 (b.date_token, 'Record found.', 'No records found.') AS
is_found
FROM (SELECT To_date (a.month
|| '/'
|| b.day
|| '/'
|| a.year, 'MM/DD/YYYY') AS date_token
FROM (SELECT To_char (Extract (month FROM a.punch_time)) AS
MONTH,
To_char (Extract (year FROM a.punch_time)) AS
YEAR
FROM time_log_temp a
GROUP BY To_char (Extract (month FROM a.punch_time)),
To_char (Extract (year FROM a.punch_time))) a
join (SELECT To_char (ROWNUM) AS DAY
FROM dual
CONNECT BY ROWNUM <= 31) b
-- I placed this condition to eliminate dates such as February 31, etc.
-- and it works unless I uncomment the WHERE clause below.
ON b.day <= Extract (day FROM Last_day (
To_date (a.month
|| '/1/'
|| a.year,
'MM/DD/YYYY')))) a
left join (SELECT Trunc (a.punch_time) AS date_token
FROM time_log_temp a
GROUP BY Trunc (a.punch_time)) b
ON b.date_token = a.date_token
ORDER BY 1,
2)
SELECT *
FROM inter
-- WHERE Trunc(date_token, 'MONTH') = '1-JAN-2018'