使用add_months时,oracle中的有效月份不是

时间:2015-03-19 10:06:36

标签: php sql oracle to-date sysdate

我在查询中提供了以下代码。

    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

有人能说出我为什么会收到此错误吗?

2 个答案:

答案 0 :(得分: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被设置为除了&#39; mm-yyyy&#39;以外的东西,你就会遇到问题。默认的nls_date_format参数是&#39; DD-MON-YY&#39;,这很可能是您的值设置为。

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

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


如果你按照Lalit的要求发送一个已经是日期的东西,这是隐式to_char的证据 - 一个涉及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()

答案 1 :(得分:1)

错误在于:

  

to_date(sysdate,&#39; MM-YYYY&#39;)

让我们看看原因:

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&#39; answer,了解有关Oracle在应用 to_date <时必须执行的隐式转换的见解/ strong> 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