1. 程式人生 > 其它 >Incorrect datetime value ‘2021-02‘ for function str_to_date

Incorrect datetime value ‘2021-02‘ for function str_to_date

技術標籤:MySQLmysql

在使用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', '');