Приведение ДАТА возвращает ошибку "Недопустимый месяц" - PullRequest
0 голосов
/ 20 сентября 2018

Мой финансовый год начинается 1 мая и заканчивается 30 апреля. Я пытаюсь вернуть дату начала финансового года с помощью выписки CASE.

Т.е.

CAST(
         CASE
             WHEN TO_NUMBER (TO_CHAR (GET_DATE, 'MM')) IN (11,
                                                           12,
                                                           5,
                                                           6,
                                                           7,
                                                           8,
                                                           9,
                                                           10)
             THEN
                   '05/01/'
                || TO_NUMBER (TO_CHAR (TRUNC (get_date, 'year'), 'YYYY'))
             WHEN TO_NUMBER (TO_CHAR (GET_DATE, 'MM')) IN (1,
                                                           2,
                                                           3,
                                                           4)
             THEN
                   '05/01/'
                || TO_NUMBER (TO_CHAR (TRUNC (get_date, 'year'), 'YYYY') - 1)
          END AS DATE)

Я получаю "Недопустимый месяц ", когда я использую актерский состав, но когда я снимаю его, по умолчанию используется номер.В любом случае, я не получаю желаемых результатов.

Ответы [ 5 ]

0 голосов
/ 20 сентября 2018

Расширяя ответ @ CaiusJard, вы можете получить начало финансового года с помощью:

add_months(trunc(add_months(get_date, -4), 'YYYY'), 4)
  • add_months(get_date, -4) вычитает четыре месяца из даты начала, поэтому значениес января по апрель будет скорректирована на дату с сентября по декабрь предыдущего года .Так, например, 2018-03-11 станет 2017-11-11.Но даты, начиная с мая, останутся в том же году, поэтому, например, 2018-07-04 становится 2018-03-04.

  • Затем trunc(..., 'YYYY') усекает это скорректированное значение допервый день своего года.Таким образом, 2018-03-11 становится 2017-11-11, который становится 2017-01-01;и 2018-07-04 становится 2018-03-04, который становится 2018-01-01.

  • Затем внешний add_months(..., 4) добавляет четыре месяца назад к , что скорректированное значение.Таким образом, 2018-03-11 становится 2017-11-11, который становится 2017-01-01, который, наконец, становится 2017-05-01;и 2018-07-04 становится 2018-03-04, который становится 2018-01-01, который окончательно становится 2018-05-01.

Чтобы получить последний день финансового года, выможет сделать то же самое, но добавить дополнительные 12 месяцев в окончательном расчете - что даст вам начало следующего финансового года - и затем вычесть один день:

add_months(trunc(add_months(get_date, -4), 'YYYY'), 16) - 1

Подробнеео функциях add_months() и trunc() и о арифметике дат в документации.

Демонстрация с фиктивными датами вCTE, чтобы показать шаги настройки:

with your_table (get_date) as (
  select add_months(date '2018-01-15', level)
  from dual
  connect by level <= 30
)
select get_date,
  add_months(get_date, -4) as adjusted_month,
  trunc(add_months(get_date, -4), 'YYYY') as adjusted_year,
  add_months(trunc(add_months(get_date, -4), 'YYYY'), 4) as start_date,
  add_months(trunc(add_months(get_date, -4), 'YYYY'), 16) - 1 as end_date
from your_table
order by get_date;

GET_DATE   ADJUSTED_M ADJUSTED_Y START_DATE END_DATE  
---------- ---------- ---------- ---------- ----------
2018-02-15 2017-10-15 2017-01-01 2017-05-01 2018-04-30
2018-03-15 2017-11-15 2017-01-01 2017-05-01 2018-04-30
2018-04-15 2017-12-15 2017-01-01 2017-05-01 2018-04-30
2018-05-15 2018-01-15 2018-01-01 2018-05-01 2019-04-30
2018-06-15 2018-02-15 2018-01-01 2018-05-01 2019-04-30
2018-07-15 2018-03-15 2018-01-01 2018-05-01 2019-04-30
...
2019-01-15 2018-09-15 2018-01-01 2018-05-01 2019-04-30
2019-02-15 2018-10-15 2018-01-01 2018-05-01 2019-04-30
2019-03-15 2018-11-15 2018-01-01 2018-05-01 2019-04-30
...
2020-02-15 2019-10-15 2019-01-01 2019-05-01 2020-04-30
2020-03-15 2019-11-15 2019-01-01 2019-05-01 2020-04-30
2020-04-15 2019-12-15 2019-01-01 2019-05-01 2020-04-30
2020-05-15 2020-01-15 2020-01-01 2020-05-01 2021-04-30
2020-06-15 2020-02-15 2020-01-01 2020-05-01 2021-04-30
2020-07-15 2020-03-15 2020-01-01 2020-05-01 2021-04-30

db <> fiddle


Как отмечено в других местах в комментариях, ваш исходный код содержит ошибку, потому что cast(<string> as date) использует настройки NLS вашего сеанса, и строимая вами строка не соответствует этому параметру.Вы можете использовать to_date() вместо case, чтобы предоставить маску ожидаемого формата (см. Ответ @ alvalongo!).

0 голосов
/ 20 сентября 2018

Для Oracle это дает начало финансового года для любой даты.

Просто замените функцию "sysdate" переменной типа DATE или именем столбца типа DATE:

select /* for Oracle */
       to_date(CASE 
                 WHEN extract(month from sysdate)<5 then
                        extract(year from sysdate)-1
                 ELSE 
                   extract(year from sysdate)
               end||'-05-01',
               'yyyy-mm-dd') as start_fiscal_year
from dual;

Тестирование базы данных Oracle с использованием анонимного блока:

Declare
 /*=========================================================================================
  --  objective: calculate Start fiscal date  
  --             Fisacal year starts on May 1 and ends April 30
  --
  --  /11209020/privedenie-data-vozvraschaet-oshibku-nedopustimyi-mesyats
  --
  --  Database: Oracle
  --
  --  2018-09-20 alvalongo
  ==========================================================================================*/
  dtStart_date         date:=to_date('2018-01-10','yyyy-mm-dd');
  dtAny_date           date;
  dtStart_fiscal_date  date;
Begin
    dbms_output.put_line('I |ANY_DATE  |START_FISCAL_YEAR');
   for nuI in 0..24 loop
       dtAny_date:=add_months(dtStart_date,nuI);
       --
       select to_date(CASE 
                        WHEN extract(month from dtAny_date)<5 then
                             extract(year from dtAny_date)-1
                        ELSE 
                          extract(year from dtAny_date)
                      end||'-05-01','yyyy-mm-dd') as start_fiscal_year
       into dtStart_fiscal_date
       from dual;
       if extract(month from dtAny_date)=5 then
          dbms_output.put_line('--|----------|----------');
       end if;
       dbms_output.put_line(lpad(nuI,2)
                            ||'|'||to_char(dtAny_date         ,'yyyy-mm-dd')
                            ||'|'||to_char(dtStart_fiscal_date,'yyyy-mm-dd')
                           );
   End loop;
End;
/

Вывод с использованием буфера dbms_output:

I |ANY_DATE  |START_FISCAL_YEAR
 0|2018-01-10|2017-05-01
 1|2018-02-10|2017-05-01
 2|2018-03-10|2017-05-01
 3|2018-04-10|2017-05-01
--|----------|----------
 4|2018-05-10|2018-05-01
 5|2018-06-10|2018-05-01
 6|2018-07-10|2018-05-01
 7|2018-08-10|2018-05-01
 8|2018-09-10|2018-05-01
 9|2018-10-10|2018-05-01
10|2018-11-10|2018-05-01
11|2018-12-10|2018-05-01
12|2019-01-10|2018-05-01
13|2019-02-10|2018-05-01
14|2019-03-10|2018-05-01
15|2019-04-10|2018-05-01
--|----------|----------
16|2019-05-10|2019-05-01
17|2019-06-10|2019-05-01
18|2019-07-10|2019-05-01
19|2019-08-10|2019-05-01
20|2019-09-10|2019-05-01
21|2019-10-10|2019-05-01
22|2019-11-10|2019-05-01
23|2019-12-10|2019-05-01
24|2020-01-10|2019-05-01
Total execution time 517 ms
0 голосов
/ 20 сентября 2018

Я попробовал следующий код, и он работал для меня.DATE - это встроенное ключевое слово, поэтому мы не можем использовать его в качестве псевдонима столбца.Я изменил это на FS_START_DATE.

 SELECT SYSDATE,  TO_DATE(CASE
     WHEN TO_NUMBER (TO_CHAR (SYSDATE, 'MM')) IN (11, 12, 5,6,7, 8,9, 10)
     THEN '05/01/' || TO_NUMBER (TO_CHAR (TRUNC (SYSDATE, 'year'), 'YYYY'))
     WHEN TO_NUMBER (TO_CHAR (SYSDATE, 'MM')) IN (1, 2, 3,4)
     THEN  '05/01/' || TO_NUMBER (TO_CHAR (TRUNC (SYSDATE, 'year'), 'YYYY') - 1)
  END,'MM/DD/YYYY') AS FS_START_DATE FROM DUAL;

Я использую функцию TO_DATE, и это возвращает меня 01-MAY-2018.

0 голосов
/ 20 сентября 2018

Это должно работать, если вы хотите сохранить оператор CASE

select CASE WHEN                               
MONTH(CURRENT_DATE) < 5 THEN                   
YEAR(CURRENT_DATE)-1    ELSE YEAR(CURRENT_DATE)
end                                            
0 голосов
/ 20 сентября 2018

Просто вычтите 4 (четыре) месяца из вашей даты и вытяните из нее год (используйте усечение, чтобы уменьшить его до года), затем добавьте 4 (четыре) месяца назад к

SELECT 
  ADD_MONTHS(
    TRUNC(
      ADD_MONTHS( <yourdate> ,-4),
      'YEAR'),
  4) 
FROM DUAL;

Что касаетсяпочему это работает:

We have some example dates:              25-04-2009 13-07-2009
These are in the fiscal years beginning: 01-05-2008 01-05-2009
We subtract 4 months from the date:      25-12-2008 13-03-2009
We trunc down to the year start:         01-01-2008 01-01-2009
We add 4 months back on to get to May:   01-05-2009 01-05-2009

Почему это хорошо / лучше, чем преобразование в строку и обратно?Ну, это причина прямо здесь.Даты представлены в виде числа, и этот метод сохраняет его в виде числа и полностью работает без математики;сложение, округление и вычитание.Всегда лучше избегать ненужных преобразований типов данных, потому что они медленные, ресурсоемкие и могут привести к непредвиденным ошибкам преобразования

Использование TRUNC с датами - одна из самых крутых вещей, которые Oracle делает с датами, которые другие базы данных просто могут 'т ручкой.Возможность взять любую дату и TRUNC () ее в начале года / месяца / дня / часа / минуты / дня недели и т. Д. Месяца очень полезна в отчетах, где события регистрируются с точностью до миллисекунды, но вы хотите суммировать или работатьс ними в терминах «количество вещей, которые произошли на этой неделе / ​​месяц» и т. д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...