最近看了兩篇關於timestamp的文章,正好手頭有MySQL5的版本要升級。翻了翻版本5、6、7的文檔,做了點筆記。
兩篇博客地址:
MySQL的TIMESTAMP類型字段非空和默認值屬性的影響
MySQL遷移后timestamp列cannot be null
date:
日期。有效范圍是‘1000-01-01’至‘9999-12-31’。檢索和顯示格式為‘YYYY-MM-DD’
datetime:
timestamp:
包含日期和時間。有效范圍是'1970-01-01 00:00:01' UTC至'2038-01-19 03:14:07' UTC。timestamp的值存儲的是自'1970-01-01 00:00:00'但現在的秒數。timestamp不能存儲1970-01-01 00:00:00‘’,因為這個表示經過了0秒,而0在timestamp中表示‘0000-00-00 00:00:00’。
在MySQL 5.5中,表中的第一個timestamp列如果沒有顯式指定內容,會自動被設置為最近修改的日期和時間。這使得timestamp列對於記錄插入和更新的時間戳特別有用。如果將timestamp列指定為NULL,就表示將對應的列值設置成了當前的日期和時間。
如果開啟了mixed sql mode,timestamp和datetime一樣了。創建表的時候會將timestamp轉換成datetime。從5.7.2開始,mixed sql mode變得過期了。
存儲的時候,MySQL將timestamp的值從當前的時區轉換成UTC時間進行存儲;檢索的時候從UTC轉成當前的時區。(其它類型,如datetime不會有這種轉換)。如果存儲進去后修改過時區,就可能會檢索出不同於原來的值。缺省情況下,每個連接的當前時區是mysql server的時區。
datetime或timestamp值可以包括尾隨小數秒部分,精度最高可達微秒(6 位)。在MySQL5中,盡管可以識別此小數部分,但它會從存儲在datetime或timestamp列中的值中丟棄。從MySQL5.6.4開始,這部分的值不再被丟棄。格式也就變成了'YYYY-MM-DD hh:mm:ss[.fraction]',datetime的取值范圍變成了'1000-01-01 00:00:00.000000'至'9999-12-31 23:59:59.999999';timestamp的取值范圍變成了'1970-01-01 00:00:01.000000'至'2038-01-19 03:14:07.999999'
無效的date、datetime、timestamp的值會被轉換成適當的0格式,如('0000-00-00' 或'0000-00-00 00:00:00')。
MySQL中日期值解釋的一些特性:
·MySQL允許指定為字符串的值的“寬松”格式,其中任何標點字符都可以用作日期部分或時間部分之間的分隔符。在某些情況下,這種語法可能具有欺騙性。例如,諸如“10:11:12”之類的值可能由於“:”分隔符而看起來像時間值,但如果在日期上下文中使用,則被解釋為年份“2010-11-12”。 值“10:45:15”被轉換為“0000-00-00”,因為“45”不是一個有效月份。
在日期和時間部分與小數秒部分之間識別的唯一分隔符是小數點。
·月和日值必須是有效的,而不僅僅是分別在1到12和1到31的范圍內。禁用strict mode后,諸如“2004-04-31”之類的無效日期將轉換為“0000-00-00”並生成警告;啟用strict mode后,無效日期會產生錯誤。要允許此類日期,請啟用 ALLOW_INVALID_DATES。
·MySQL不接受在日或月中包含零的TIMESTAMP值或無效日期的值。此規則的唯一例外是特殊的“零”值 '0000-00-00 00:00:00',前提是SQL mode允許此值。確切的行為取決於是否啟用了strict sql模式和no_zero_date模式。
·包含2位數年份值的日期不明確,因為世紀未知。MySQL使用以下規則解釋2位年份值:
--00-69范圍內的年份值變為 2000-2069。
--70-99范圍內的年份值變為 1970-1999。
MySQL5.5中的timestamp和datetime列的自動初始化和自動更新
timestamp數據類型具有自動初始化和更新成當前日期和時間(當前的時間戳)的功能。是否使用這些特性,由用戶決定:
·一個表中只有一個timestamp列在初始化的時候可以用當前時間戳作為默認值或自動更新的值、或者同時作為默認值和自動更新值。但不能作為一個timestamp列的默認值、通過作為另一個timestamp列的自動更新值。
·如果timestamp列是自動初始化的,會將當前時間戳作為默認值
·如果timestamp列是自動更新的,行中任何列的修改都會將timestamp列修改成當前時間戳。
自動初始化或自動更新功能,可以通過關鍵字default current_timestamp、on update current_timestamp來指定。
如果指定了no_zero_data sql模式,就不可以指定為default 0了,0或‘0000-00-00 00:00:00’會被拒絕。
MySQL5.6中的timestamp和datetime列的自動初始化和自動更新
從5.6.5開始,timestamp和time列可以自動初始化或自動更新成當前時間戳,即current timestamp。
在5.6.5之前,只有timestamp列可以自動初始化或自動更新成當前時間戳,且一個表中最多只有一個timetamp列具備該特性。
對於表中的timestamp、datetime列,可以將當前時間戳指定為列的默認值、自動更新值、或者同時指定為默認值和自動更新值。
1.插入行時,將當前時間戳指定為自動初始值
2.行中列發生變更時,自動更新成當前時間戳;如果其他列的值被修改成當前的值,就會自動更新timestamp、datetime列的值
如果關閉了explicit_defaults_for_timestamp變量,可以通過指定為NULL值,將任何timestamp列(datetime列不是如此)初始化或更新成當前時間戳,列被定義為允許為NULL例外。
指定自動初始化、或自動更新屬性,使用default current_timestamp、on update current_timestamp子句定義。二者的定義順序不重要。
default語句也可以指定顯式的默認值,比如default 0、default ‘2000-02-02 00:00:00’。default 0 是否會會產生警告或錯誤,取決於是否開啟了strict sql mode或no_zero_date sql mode。
1.同時指定默認值和自動更新特性
create table t1 ( ts timestamp default current_timestamp on update current_timestamp, dt datetime default current_timestamp on update current_timestamp );
2.指定默認值
create table t1 ( ts timestamp default current_timestamp, dt datetime default current_timestamp );
像下面這樣,就沒有自動初始化和自動更新的特性了:
create table t1 ( ts timestamp default 0, dt datetime default 0 );
3.指定默認常量值和自動更新
create table t1 ( ts timestamp default 0 on update current_timestamp, dt datetime default 0 on update current_timestamp );
4.指定自動更新
如果timestamp沒有顯式指定默認值為null,則其默認值是0;datetime的默認值是null,如果指定為not null,默認值是0。
create table t1 ( ts1 timestamp on update current_timestamp, -- default 0 ts2 timestamp null on update current_timestamp -- default null );
create table t1 ( dt1 datetime on update current_timestamp, -- default null dt2 datetime not null on update current_timestamp -- default 0 );
timestamp、datetime列如果沒有顯式定義,就不開啟自動初始化和自動更新功能。但是也有例外,如果關閉了explicit_default_for_timestamp變量,第一個沒有使用default current_timestamp、on update current_timestamp定義的timestamp列同時具備這兩種屬性。開啟了explicit_default_for_timestamp變量,就必須顯式定義才行。
來分析以下,如下定義的表:
create table t1 ( ts1 timestamp default 0, ts2 timestamp default current_timestamp on update current_timestamp); create table t2 ( ts1 timestamp null, ts2 timestamp default current_timestamp on update current_timestamp); create table t3 ( ts1 timestamp null default 0, ts2 timestamp default current_timestamp on update current_timestamp);
·每個表中,第一個timestamp列沒有定義自動初始化、自動更新的功能。
·表中ts1處理null值的方式是不同的,t1.ts1是not null,給其賦予NULL會將其值設置成當前時間戳;t2.ts1和t3.ts1支持null,給其賦予NULL就會將其值設置成NULL。
·t2.ts1支持null,默認值是null;t3.ts1支持null,但是默認值是0。
MySQL5.6之前自動初始化和自動更新存在以下限制:
1.default current_timestamp、on update current_timestamp不能用於datetime列。
2.每個表中只能有一個timestamp列使用default current_timestamp、on update current_timestamp。
timestamp初始化和null屬性
如果explicit_defaults_for_timestamp變量被關閉了。timestamp列默認是not null的,不能包含null值;賦為null,會變成當前時間戳。如果想包含null值,需要顯式定義null,這樣的話默認值就是null
