Конвертировать в формат даты оракул

У меня есть поле c_days в таблице my_table, которое принимает числовые значения от 1 до 31. В этом поле числа от 1 до 9 являются однозначными.

Пишу условие, если c_day больше сегодняшнего, то нужно отображать c_day в формате даты to_date, если меньше, то отображать c_day в формате даты, только следующий месяц.

Например, c_day равно 14, а сегодня у нас 8 число, значит нужно вывести дату 14.02.2023, Если c_day равно 5, то нужно вывести дату следующего месяца 05.03.2023

Я сделал что-то вроде этого:

SELECT 
   C_DAY,
   CASE
     WHEN C_DAY >= TO_CHAR(SYSDATE, 'DD') THEN 
       TO_DATE(C_DAY || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
     WHEN C_DAY < TO_CHAR(SYSDATE, 'DD') THEN
       TO_DATE(C_DAY || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
     WHEN C_DAY IS NULL THEN
       null
   END AS new_field
FROM my_table

Проблема в том, что конечный результат не преобразуется в формат даты, я думал, что это причина того, что даты могут отображаться как 1.03.2023, 7.03.2023, поэтому я попытался преобразовать его в

TO_CHAR(C_DAY, 'fm00')

и сделал это:

SELECT 
   C_DAY,
   CASE
     WHEN TO_CHAR(C_DAY, 'fm00') >= TO_CHAR(SYSDATE, 'DD') THEN 
       TO_DATE(TO_CHAR(C_DAY, 'fm00') || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
     WHEN TO_CHAR(C_DAY, 'fm00') < TO_CHAR(SYSDATE, 'DD') THEN
       TO_DATE(TO_CHAR(C_DAY, 'fm00') || '.' || TO_CHAR(SYSDATE, 'MM') || '.' || TO_CHAR(SYSDATE, 'YYYY'), 'dd.mm.yyyy')
     WHEN C_DAY IS NULL THEN
       null
   END AS new_field
FROM my_table

Но он даже не работает, он показывает ошибку ора

Посмотрите на свой код. Независимо от того, больше ли C_DAY, чем TO_CHAR(SYSDATE, 'DD') или нет, вы возвращаете одно и то же выражение! Вы также можете написать это короче TO_DATE(C_DAY || TO_CHAR(SYSDATE, '.MM.YYYY'), 'DD.MM.YYYY')

Wernfried Domscheit 08.02.2023 08:20

Конечно, оно преобразуется в значение DATE, иначе вы получите ошибку. Возможно, вас не устраивает формат отображения (по умолчанию).

Wernfried Domscheit 08.02.2023 08:23
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
2
67
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вот один из вариантов:

SQL> alter session set nls_date_format = 'dd.mm.yyyy';

Session altered.

SQL> WITH
  2     my_table (c_day)
  3     AS
  4        (SELECT 14 FROM DUAL
  5         UNION ALL
  6         SELECT 5 FROM DUAL
  7         UNION ALL
  8         SELECT 30 FROM DUAL)
  9  SELECT c_day,
 10         TO_DATE (
 11               LPAD (LEAST (c_day, TO_CHAR (LAST_DAY (SYSDATE), 'dd')), 2, '0')
 12            || '.'
 13            || TO_CHAR (
 14                  CASE
 15                     WHEN c_day < TO_CHAR (SYSDATE, 'dd')
 16                     THEN
 17                        ADD_MONTHS (SYSDATE, 1)
 18                     ELSE
 19                        SYSDATE
 20                  END,
 21                  'mm.yyyy'),
 22            'dd.mm.yyyy') AS result
 23    FROM my_table;

     C_DAY RESULT
---------- ----------
        14 14.02.2023
         5 05.03.2023
        30 28.02.2023

SQL>

еще одна ошибка ora-01858

Andrey Romanov 08.02.2023 08:11

Кстати, бывает и такой случай, февраль заканчивается 28 числа, и если c_day равно 29, 30, 31, может из-за этого у меня вылетает ошибка, как этого избежать?

Andrey Romanov 08.02.2023 08:13

Что вы хотите сделать в таком случае?

Littlefoot 08.02.2023 08:23

Я установил его на последний день текущего месяца; см. отредактированный код.

Littlefoot 08.02.2023 08:27

Я не знаю почему, но когда я пытаюсь использовать ваш выбор с моей основной таблицей, я получаю сообщение об ошибке ORA-01858: нечисловой символ был найден там, где ожидался числовой. Я вывожу все уникальные значения, это числа от 1 до 31 и null

Andrey Romanov 08.02.2023 09:33

Вы уверены, что использовали именно тот код, который я разместил? Похоже, вы использовали другую модель формата даты (например, используя ИМЯ месяца (например, ДД-МОН-ГГГГ), а не его номер (например, ДД.ММ.ГГГГ)).

Littlefoot 08.02.2023 09:55

Давайте продолжим обсуждение в чате.

Andrey Romanov 08.02.2023 10:57

Насколько я понимаю ваш вопрос, одним из решений может быть это

SELECT 
   C_DAY,
   CASE
     WHEN C_DAY >= TO_CHAR(SYSDATE, 'DD') THEN 
       ADD_MONTHS(TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM-')||C_DAY , 'YYYY-MM-DD'), 1)
     WHEN C_DAY < TO_CHAR(SYSDATE, 'DD') THEN
       TO_DATE(TO_CHAR(SYSDATE, 'YYYY-MM-')||C_DAY , 'YYYY-MM-DD')
   END AS new_field
FROM my_table

Функция ADD_MONTHS работает следующим образом:

Если date является последним днем ​​месяца или если в результирующем месяце меньше дней, чем дневной компонент date, то результатом является последний день результирующего месяца. В противном случае результат имеет тот же компонент дня, что и date.

Я думаю, что компонент «день» должен отражать значение столбца C_DAY, а не SYSDATE.

Littlefoot 08.02.2023 08:28

@Littlefoot правильно, я обновил его. Но все еще нуждается в тонкой настройке, если C_DAY больше, чем количество дней в текущем месяце. Ваш ответ лучше!

Wernfried Domscheit 08.02.2023 08:32

Теперь, кхм, это не сработает, если C_DAY = 30 (поскольку в феврале не так уж много дней) :)

Littlefoot 08.02.2023 08:33
Ответ принят как подходящий

Вы можете сделать это без каких-либо преобразований строки в дату (или наоборот), используя:

SELECT C_DAY,
       LEAST(
         ADD_MONTHS(
           TRUNC(SYSDATE, 'MM'),
           CASE WHEN c_day <= EXTRACT(DAY FROM SYSDATE) THEN 0 ELSE 1 END
         ) + c_day - 1,
         LAST_DAY(
           ADD_MONTHS(
             TRUNC(SYSDATE, 'MM'),
             CASE WHEN c_day <= EXTRACT(DAY FROM SYSDATE) THEN 0 ELSE 1 END
           )
         )
       ) AS new_field
FROM   my_table

Что для примера данных:

CREATE TABLE my_table(c_day) AS
  SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 31;

Выходы:

C_DAY НОВОЕ ПОЛЕ 1 2023-02-01 00:00:00 2 2023-02-02 00:00:00 3 03.02.2023 00:00:00 4 2023-02-04 00:00:00 5 2023-02-05 00:00:00 6 2023-02-06 00:00:00 7 2023-02-07 00:00:00 8 2023-02-08 00:00:00 9 2023-03-09 00:00:00 10 2023-03-10 00:00:00 11 2023-03-11 00:00:00 12 2023-03-12 00:00:00 13 2023-03-13 00:00:00 14 2023-03-14 00:00:00 15 2023-03-15 00:00:00 16 2023-03-16 00:00:00 17 2023-03-17 00:00:00 18 2023-03-18 00:00:00 19 2023-03-19 00:00:00 20 2023-03-20 00:00:00 21 2023-03-21 00:00:00 22 2023-03-22 00:00:00 23 2023-03-23 ​​00:00:00 24 2023-03-24 00:00:00 25 2023-03-25 00:00:00 26 2023-03-26 00:00:00 27 2023-03-27 00:00:00 28 2023-03-28 00:00:00 29 2023-03-29 00:00:00 30 2023-03-30 00:00:00 31 2023-03-31 00:00:00

рабочий пример

Все работает, спасибо чувак, у меня такой же вопрос, можешь помочь?

Andrey Romanov 08.02.2023 11:22

Другие вопросы по теме