Я дал следующий код в запросе.
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», что, скорее всего, равно значению, заданному вами.
Если все, что вы хотели сделать, это добавить add_months к 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, ‘MM-YYYY’)
Посмотрим почему:
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 monthSQL>
Вам не нужно снова конвертировать sysdate в дату. Удалить to_date
и просто использовать SYSDATE.
НОТА В качестве дополнительной информации, пожалуйста, посмотрите на @ Boneist’s ответ для понимания относительно неявного преобразования, которое Oracle вынужден делать при применении на свидание на 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