日期对指定的月份无效

时间:2011-12-31 12:50:40

标签: sql oracle

运行此Oracle SQL语句时遇到问题:

SELECT * 
  FROM tbl_content
 WHERE last_updated >= (systimestamp - INTERVAL '1' month(1)) 
 ORDER BY last_updated desc  

这个错误:

    java.sql.SQLException: ORA-01839: date not valid for month specified

    at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:330)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:287)
    at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:742)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:212)
    at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:951)
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1053)
    at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:835)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1123)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3284)
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3328)
    at com.vtdd.sms.content.xskt.XsktService.getKQXSFollowArea(XsktService.java:4044)
    at com.vtdd.sms.content.xskt.XsktService.getMessages(XsktService.java:421)
    at com.vht.sms.content.ContentAbstract.getSubmitMessages(ContentAbstract.java:47)
    at com.vht.sms.content.ContentFactory.getSubmitMessages(ContentFactory.java:335)
    at com.vht.sms.content.ContentFactory.run(ContentFactory.java:62)
    at java.lang.Thread.run(Thread.java:662)  

你能告诉我出了什么问题吗?

2 个答案:

答案 0 :(得分:7)

首先,你为什么要使用systimestamp?如果你想要这个月,那么肯定sysdate就足够了吗?其次,我喜欢 - 即个人偏好 - 非常清楚发生了什么。 Oracle有一个add_months函数,可以执行您想要的操作。所以你的查询很容易:

SELECT * 
  FROM tbl_content
 WHERE last_updated >= add_months(sysdate, -1) 
 ORDER BY last_updated desc

答案 1 :(得分:4)

实际上错误的是interval arithmetic没有调整天数 - 请参阅链接中的第6个子弹:

  

当间隔计算返回日期时间值时,结果必须是实际的日期时间值,否则数据库将返回错误。

ADD_MONTHS呢;正如那个链接所说:

  

如果日期是该月的最后一天,或者结果月份的日期少于日期的日期组成部分,那么结果就是结果月份的最后一天。

所以,ADD_MONTHS(DATE '2011-12-31', -1)给你2011-11-30,而DATE '2011-12-31' - INTERVAL '1' MONTH试图给你2011-11-31,正如消息所说,这不是一个有效的日期。

(如果这种行为实际上是错误的,这是有争议的;这是意料之外的,但我相信它符合ANSI。有时你可能希望它以这种方式工作,虽然我想不出任何......)