2

我在查询中给出了以下代码。

    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

谁能告诉我为什么会收到此错误?

4

2 回答 2

5

永远不要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”,这很可能是您设置的值。

如果您只想将_months 添加到当月的第一天,那么您应该使用TRUNC(),例如:

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


这是隐式 to_char 的证明,如果您按照 Lalit 的要求对已经是日期的内容进行 to_date - 涉及 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()过滤条件中的 。

于 2015-03-19T10:28:39.677 回答
1

错误在这里:

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 month


SQL>

您无需将 sysdate 再次转换为日期。删除to_date并仅使用SYSDATE

注意作为附加信息,请查看@Boneist 的答案,以了解Oracle 在应用to_date on时强制执行的隐式转换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
于 2015-03-19T10:20:29.440 回答