Недействительный месяц в oracle при использовании add_months

Я дал ниже код в запросе.

where to_date(cal_wid,'yyyymmdd') between add_months(to_date(sysdate, 'MM-YYYY'),-12) and to_date(sysdate, 'MM-YYYY') 

Я получаю следующую ошибку. (Я делаю на сервере Xampp)

  Warning: oci_execute(): ORA-01843: not a valid month in C:\xampp\htdocs\xxx\index.php on line 149 Warning: oci_fetch_array(): ORA-24374: define not done before fetch or execute and fetch in C:\xampp\htdocs\xxx\index.php on line 160 

Может кто-нибудь сказать, почему я получаю эту ошибку?

Никогда, никогда не используйте TO_DATE() для того, что уже является DATE . Причина этого заключается в том, что Oracle будет вынуждена сделать некоторые неявные преобразования, чтобы следовать вашим пожеланиям:

TO_DATE(sysdate, 'mm-yyyy')

действительно выполняется как

TO_DATE(TO_CHAR(sysdate, '<default nls_date_format parameter>'), 'mm-yyyy')

поэтому, если ваш nls_date_format настроен на нечто, отличное от «mm-yyyy», у вас будут проблемы. Параметр nls_date_format по умолчанию – «DD-MON-YY», что более чем вероятно для значения, на которое установлено значение.

Если все, что вы хотели сделать, это добавить_месяца к 1-му из текущего месяца, то вы должны использовать TRUNC() , например:

add_months(trunc(sysdate, 'MM'),-12)


Вот доказательство неявного to_char, если вы to_date то, что уже является датой, по просьбе Lalit – план выполнения базового запроса с участием to_date (sysdate):

 SQL_ID 3vs3gzyx2gtcn, child number 0 ------------------------------------- select * from dual where to_date(sysdate) < sysdate Plan hash value: 3752461848 ---------------------------------------------------------------------------- | Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | |* 1 | FILTER | | | | | | | 2 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TO_DATE(TO_CHAR(SYSDATE@!))<SYSDATE@!) 

Вы можете четко видеть TO_CHAR() в состоянии фильтра.

Ошибка здесь:

to_date (sysdate, «ММ-ГГГГ»)

Давайте посмотрим, почему:

 SQL> select to_date(sysdate, 'MM-YYYY') from dual; select to_date(sysdate, 'MM-YYYY') from dual * ERROR at line 1: ORA-01843: not a valid month SQL> 

Вам не нужно снова преобразовывать sysdate в дату. Удалите to_date и просто используйте SYSDATE .

ПРИМЕЧАНИЕ. В качестве дополнительной информации, пожалуйста, посмотрите на ответ @ Boneist на предмет понимания неявного преобразования, которое Oracle вынужден делать при применении to_date в SYSDATE .

Вы используете to_date для преобразования строки в дату. Для расчета даты вам просто нужно использовать значение даты.

Например,

 SQL> WITH DATA AS( 2 SELECT '20150101' cal_wid FROM DUAL 3 ) 4 SELECT * 5 FROM DATA 6 WHERE to_date(cal_wid,'yyyymmdd') 7 BETWEEN add_months(SYSDATE,-12) 8 AND SYSDATE 9 / CAL_WID -------- 20150101 SQL> 

Измените свой запрос как:

 WHERE to_date(cal_wid,'yyyymmdd') BETWEEN add_months(SYSDATE, -12) AND SYSDATE