Oracle interval '1' YEAR寫法,在瑞年2.29號當前會報錯,這是由於Oracle的interval電腦製造成的,替代寫法add_months(TO_DATE('2020-02-29','yyyy-MM-dd'),-12) ...
- 2.28日,客戶微信公眾號更新賬單列表功能:業主群里反饋用戶查到的賬單記錄不是自己的,經驗證和推測是同事寫死了用戶編號。好吧!!!在家辦公,有點馬虎,表示理解吧。
- 2.29日,星期六,懶覺還沒睡醒,業主群里反饋賬單查不到了。I'm Angry,直接把問題截圖轉發到了小組溝通群里。
轉過頭來一想,不對呀,昨天更新後是可以正常使用的呀。這家伙也不會這麼用工,加班又給更新一版。感覺不對,查日誌。
賬單列表是預設載入近一年的,也沒有傳遞時間相關的信息呀,怎麼就指定的月份日期無效呢。直接在後臺執行對應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!!!