【IT168 技術】MySQL資料庫中有五種與日期和時間有關的數據類型,各種日期數據類型所佔空間如表2-1所示。
DATETIME和 DATE
DATETIME佔用8位元組,是佔用空間最多的一種日期類型。它既顯示了日期,同時也顯示了時間。其可以表達的日期範圍為「1000-01-01 00:00:00」到「9999-12-31 23:59:59」。
DATE佔用3位元組,可顯示的日期範圍為「1000-01-01」到「9999-12-31」。
在MySQL資料庫中,對日期和時間輸入格式的要求是非常寬鬆的,以下的輸入都可以視為日期類型。
·2011-01-01 00:01:10
·2011/01/01 00+01+10
·20110101000110
·11/01/01 00@01@10
其中,最後一種類型中的「11」有些模稜兩可,MySQL資料庫將其視為2011還是1911呢?下面來做個測試:
mysql> SELECT CAST('11/01/01 00@01@10' AS DATETIME) AS datetime\G;
*************************** 1. row ***************************
datetime: 2011-01-01 00:01:10
1 row in set (0.00 sec)
可以看到資料庫將其視為離現在最近的一個年份,這可能不是一個非常好的習慣。如果沒有特別的條件和要求,還是在輸入時按照標準的「YYYY-MM-DD HH:MM:SS」格式來進行。在MySQL 5.5版本之前(包括5.5版本),資料庫的日期類型不能精確到微秒級別,任何的微秒數值都會被資料庫截斷,例如:
mysql> CREATE TABLE t ( a DATETIME );
Query OK, 0 rows affected (0.25 sec)
mysql> INSERT INTO t SELECT '2011-01-01 00:01:10.123456';
Query OK, 1 row affected (0.05 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2011-01-01 00:01:10
1 row in set (0.00 sec)
不過MySQL資料庫提供了函數MICROSECOND來提取日期中的微秒值,示例如下:
mysql> SELECT MICROSECOND('2011-01-01 00:01:10.123456')\G;
*************************** 1. row ***************************
MICROSECOND('2011-01-01 00:01:10.123456'): 123456
1 row in set (0.00 sec)
有意思的是, MySQL的CAST函數在強制轉換到DATETIME時會保留到微秒數,不過在插入後同樣會截斷,示例如下:
mysql> SELECT CAST('2011-02-01 00:01:10.123456' AS DATETIME) D\G;
*************************** 1. row ***************************
D: 2011-02-01 00:01:10.123456
1 row in set (0.00 sec)
mysql> INSERT INTO t
->SELECT CAST('2011-02-01 00:01:10.123456' AS DATETIME);
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2011-01-01 00:01:10
*************************** 2. row ***************************
a: 2011-02-01 00:01:10
2 rows in set (0.00 sec)
然而從MySQL 5.6.4版本開始,MySQL增加了對秒的小數部分(fractional second)的支持,具體語法為:
其中,type_name的類型可以是TIME、DATETIME和TIMESTAMP。fsp表示支持秒的小數部分的精度,最大為6,表示微秒(microseconds);默認為0,表示沒有小數部分,同時也是為了兼容之前版本中的TIME、DATETIME和TIMESTAMP類型。對於時間函數,如CURTIME()、SYSDATE()和UTC_TIMESTAMP()也增加了對fsp的支持,例如:
mysql> SELECT CURTIME(4) AS TIME\G;
*************************** 1. row ***************************
TIME: 10:22:37.4456
1 rows in set (0.00 sec)
注意 MariaDB 5.3版本就對TIME、DATETIME、TIMESTAMP類型的微秒部分進行了支持。詳細的說明可以從http://kb.askmonty.org/en/microseconds-in-mariadb中得到。
${PageNumber}
TIMESTAMP
TIMESTAMP和DATETIME顯示的結果是一樣的,都是固定的「YYYY-MM-DD HH:MM:SS」的形式。不同的是,TIMESTAMP佔用4位元組,顯示的範圍為「1970-01-01 00:00:00」UTC到「2038-01-19 03:14:07」UTC。其實際存儲的內容為「1970-01-01 00:00:00」到當前時間的毫秒數。
注意 UTC 協調世界時,又稱世界統一時間、世界標準時間和國際協調時間。它從英文Coordinated Universal Time和法文Temps Universel Cordonné而來。
TIMESTAMP類型和DATETIME類型除了在顯示時間範圍上有所不同外,還有以下不同:
在建表時,列為TIMESTAMP的日期類型可以設置一個默認值,而DATETIME不行。
在更新表時,可以設置TIMESTAMP類型的列自動更新時間為當前時間。
首先來看一個默認設置時間的例子。
mysql> CREATE TABLE t
-> ( a INT,
-> b TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-> )ENGINE=InnoDB;
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t (a) VALUES (1);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 1
b: 2011-02-02 16:42:57
1 row in set (0.01 sec)
接著來看一個執行UPDATE時更新為當前時間的例子。
mysql> CREATE TABLE t
-> ( a INT ,
-> b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-> );
mysql> INSERT INTO t SELECT 1,CURRENT_TIMESTAMP;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 1
b: 2011-02-02 16:45:40
1 row in set (0.01 sec)
# 等待一段時間
mysql> UPDATE t SET a=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
可以發現在執行UPDATE操作後,b列的時間由原來的16:45:40更新為了16:47:39。如果執行了UPDATE操作,而實際上行並沒有得到更新,那麼是不會更新b列的,例如:
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
mysql> UPDATE t SET a=2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
可以看到執行UPDATE t SET a=2並沒有改變行中的任何數據,顯示Changed:0表示該行實際沒有得到更新,故b列並不會進行相應的更新操作。
當然,可以在建表時將TIMESTAMP列設為一個默認值,也可以設為在更新時的時間,例如:
mysql> CREATE TABLE t (
-> a INT,
-> b TIMESTAMP DEFAULT ON UPDATE CURRENT_TIMESTAMP
->)ENGINE=InnoDB;
${PageNumber}
YEAR和TIME
YEAR類型佔用1位元組,並且在定義時可以指定顯示的寬度為YEAR(4)或YEAR(2),例如:
mysql> CREATE TABLE t ( a YEAR(2));
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO t SELECT '1990';
mysql> SELECT * FROM t;
+------+
| a |
+------+
| 90 |
+------+
1 row in set (0.00 sec)
對於YEAR(4),其顯示年份的範圍為1901~2155;對於YEAR(2),其顯示年份的範圍為1970~2070。在YEAR(2)的設置下,00~69代表2000~2069年。
TIME類型佔用3位元組,顯示的範圍為「-838:59:59」~「838:59:59」。有人會奇怪為什麼TIME類型的時間可以大於23。因為TIME類型不僅可以用來保存一天中的時間,也可以用來保存時間間隔,同時這也解釋了為什麼TIME類型也可以存在負值。和DATETIME類型一樣,TIME類型同樣可以顯示微秒時間,但是在插入時,資料庫同樣會進行截斷操作,例如:
mysql> CREATE TABLE t ( a TIME );
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t SELECT '14:40:20.123456';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t;
+----------+
| a |
+----------+
| 14:40:20 |
+----------+
1 row in set (0.00 sec)