Oracle interval '1' YEAR 今天報錯了


  • 2.28日,客戶微信公眾號更新賬單列表功能:業主群里反饋用戶查到的賬單記錄不是自己的,經驗證和推測是同事寫死了用戶編號。好吧!!!在家辦公,有點馬虎,表示理解吧。
  • 2.29日,星期六,懶覺還沒睡醒,業主群里反饋賬單查不到了。I'm Angry,直接把問題截圖轉發到了小組溝通群里。

轉過頭來一想,不對呀,昨天更新后是可以正常使用的呀。這家伙也不會這么用工,加班又給更新一版。感覺不對,查日志。

API網關日志

賬單列表是默認加載近一年的,也沒有傳遞時間相關的信息呀,怎么就指定的月份日期無效呢。直接在后台執行對應SQL,還是報錯。

ORA-01839: 指定月份的日期無效
01839. 00000 -  "date not valid for month specified"

看來是SQL語句的問題,但是接口最近就沒有更新呀。最終鎖定在

sysdate - interval '1' YEAR
--當然這個問題必須是在特定日期才會出現的,比如
select TO_DATE('2020-02-29','yyyy-MM-dd') - interval '1' YEAR from dual

經網上查詢,原來這個問題是因為閏年29號以及oracel的interval處理機制造成。

Query containing SYSDATE - INTERVAL '1' YEAR fails for today's date(29th February 2016)

這里先說替代寫法:

select add_months(TO_DATE('2020-02-29','yyyy-MM-dd'),-12) from dual

這里有問題的說明:

It might be disappointing, but it is to be expected. [It is mentioned in the documentation](https://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#i48042):
When interval calculations return a datetime value, the result must be an actual datetime value or the database returns an error. For example, the next two statements return errors:
SELECT TO_DATE('31-AUG-2004','DD-MON-YYYY') + TO_YMINTERVAL('0-1') FROM DUAL;
  SELECT TO_DATE('29-FEB-2004','DD-MON-YYYY') + TO_YMINTERVAL('1-0') FROM DUAL; 
The first fails because adding one month to a 31-day month would result in September 31, which is not a valid date. The second fails because adding one year to a date that exists only every four years is not valid. 

大概意思是:

Oracle的官方文檔中已經說了:interval計算返回一個datetime值,返回值必須是一個准確的datetime值,否則返回錯誤。

說白了,interval計算后,Oracle不會做轉換,比如第一種情況,沒有31號,不會幫你轉到次月1號;第二種情況,沒有29號,不會幫你轉到次月1號或本月20號。因為這樣不准確。

最后感嘆一下,自己遇到了破解了一個4年一遇的bug!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM