Incorrect datetime value ‘2021-02‘ for function str_to_date
在使用MySQL的STR_TO_DATE函式將字串轉換成Date型別的時候,會出現類似:Incorrect datetime value '2021-02' for function str_to_date的錯誤。下面來看看解決辦法。
情景復現:
(1)建立表:
create table time_table(
`year` varchar(4),
`month` varchar(2),
`day` varchar(2)
);
(2)插入資料:
INSERT INTO time_table (`year`, `month`, `day`) VALUES('2021', '03', '02');
(3)查詢資料:
select STR_TO_DATE(CONCAT(`year`,'-',`month`),'%Y-%m') from time_table;
執行語句不發生錯誤,但返回的結果為NULL:
(4)更新資料:
update time_table set month = '04' where STR_TO_DATE(CONCAT(`year`,'-',`month`),'%Y-%m') > CURRENT_DATE();
執行更新語句產生錯誤:Incorrect datetime value: '2021-03' for function str_to_date
問題原因:
產生Incorrect datetime value: '2021-03' for function str_to_date報錯的原因是對STR_TO_DATE函式的使用不當。STR_TO_DATE(引數1, 引數2),其中引數1必須是年月日格式的字串,比如:'2021-03-02'。因為CONCAT(`year`,'-',`month`)語句得到的字串只含有年月,缺少了日,不是正確的年月日格式,因此會提示錯誤。對於引數2是日期格式,形式必須和引數1保持一致,即如果引數1為'2021-03-02',那麼引數2需要為'%Y-%m-%d'。如果引數1為'2021/03/02',那麼引數2需要為'%Y/%m/%d'。
引數1和引數2格式必須一致,該特點和Java中的SimpleDateFormat特點一致,比如:
// 對應STR_TO_DATE的引數2
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm");
// 對應STR_TO_DATE的引數1
Date date = simpleDateFormat.parse("2021/03/02");
System.out.println(date);
執行該程式碼,會報錯:
Exception in thread "main" java.text.ParseException: Unparseable date: "2021/03/02"
(1)比如如下引數1(使用斜槓分割)和引數2(使用短槓分割)格式不一致,查詢語句結果為NULL:
更新語句報錯:
(2)再比如如下引數1是年月日格式,引數2是年月表示式,查詢語句仍然返回NULL:
更新語句報錯:
(3)比如如下查詢語句,引數1和引數2格式一致,都可以返回結果:
select STR_TO_DATE(CONCAT(`year`,'-',`month`, '-', `day`),'%Y-%m-%d') from time_table;
select STR_TO_DATE(CONCAT(`year`,'/',`month`, '/', `day`),'%Y/%m/%d') from time_table;
如下更新語句都可以正常執行,不提示錯誤:
update time_table set month = '04' where STR_TO_DATE(CONCAT(`year`,'-',`month`, '-', `day`),'%Y-%m-%d') > CURRENT_DATE();
update time_table set month = '04' where STR_TO_DATE(CONCAT(`year`,'/',`month`, '/', `day`),'%Y/%m/%d') > CURRENT_DATE();
解決辦法:
如果一定要使用STR_TO_DATE(CONCAT(`year`,'-',`month`),'%Y-%m')這樣的格式,也是有解決辦法的。
(1)檢視SQL_MODE
select @@SQL_MODE
會在返回結果中看見有個內容:NO_ZERO_DATE。
出現上述報錯的原因,就是這個模式的作用結果。我們可以將該模式移除,便可以解決報錯問題。
(2)移除NO_ZERO_DATE
SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_DATE', '');
將SQL_MODE中的NO_ZERO_DATE內容替換成空字串,即可將模式移除。
(3)再執行前面的UPDATE語句
語句順利執行,並且資料也被改變。
(4)再執行前面的SELECT語句
返回值不再是NULL,而是有內容了。但是內容除了年月,還包含了日,而且日期是2021-04(經過UPDATE語句修改後的資料庫值)的前一個月的最後一天。
SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_DATE', '');
該語句移除NO_ZERO_DATE模式,僅僅在當前會話內有效。當你斷開當前的資料庫連線,再重新連線,此時該模式恢復,執行UPDATE語句仍然會報錯。
全域性修改的方式是新增GLOBAL,這樣修改的方式在斷開重新連線以後,修改仍然有效。但是如果重啟MySQL服務之後就會恢復到原先的設定。
SET GLOBAL SQL_MODE = REPLACE(@@SQL_MODE, 'NO_ZERO_DATE', '');