MySQL 列數據類型(2)

11.3.1. DATETIME、DATE和TIMESTAMP類型
11.3.1.1. 自MySQL 4.1以來的TIMESTAMP屬性
DATETIME、DATE和TIMESTAMP類型是相關的。該節描述了它們的特徵,它們的類似點和不一樣點。

當你須要同時包含日期和時間信息的值時則使用DATETIME類型。MySQL以'YYYY-MM-DD HH:MM:SS'格式檢索和顯示DATETIME值。支持的範圍爲'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。(「支持」表示儘管先前的值可能工做,但沒有保證)。

當你只須要日期值而不須要時間部分時應使用DATE類型。MySQL用'YYYY-MM-DD'格式檢索和顯示DATE值。支持的範圍是'1000-01-01'到 '9999-12-31'。

TIMESTAMP列類型的屬性不固定,取決於MySQL版本和服務器運行的SQL模式。這些屬性將在本節後面描述。

可使用任何常見格式指定DATETIME、DATE和TIMESTAMP值:

·         'YYYY-MM-DD HH:MM:SS'或'YY-MM-DD HH:MM:SS'格式的字符串。容許「不嚴格」語法:任何標點符均可以用作日期部分或時間部分之間的間割符。例如,'98-12-31 11:30:45'、'98.12.31 11+30+45'、'98/12/31 11*30*45'和'98@12@31 11^30^45'是等價的。

·         'YYYY-MM-DD'或'YY-MM-DD'格式的字符串。這裏也容許使用「不嚴格的」語法。例如,'98-12-31'、'98.12.31'、'98/12/31'和'98@12@31'是等價的。

·         'YYYYMMDDHHMMSS'或'YYMMDDHHMMSS'格式的沒有間割符的字符串,假定字符串對於日期類型是有意義的。例如,'19970523091528'和'970523091528'被解釋爲'1997-05-23 09:15:28',但'971122129015'是不合法的(它有一個沒有意義的分鐘部分),將變爲'0000-00-00 00:00:00'。

·         'YYYYMMDD'或'YYMMDD'格式的沒有間割符的字符串,假定字符串對於日期類型是有意義的。例如,'19970523'和'970523'被解釋爲 '1997-05-23',但'971332'是不合法的(它有一個沒有意義的月和日部分),將變爲'0000-00-00'。

·         YYYYMMDDHHMMSS或YYMMDDHHMMSS格式的數字,假定數字對於日期類型是有意義的。例如,19830905132800和830905132800被解釋爲 '1983-09-05 13:28:00'。

·         YYYYMMDD或YYMMDD格式的數字,假定數字對於日期類型是有意義的。例如,19830905和830905被解釋爲'1983-09-05'。

·         函數返回的結果,其值適合DATETIME、DATE或者TIMESTAMP上下文,例如NOW()或CURRENT_DATE。

無效DATETIME、DATE或者TIMESTAMP值被轉換爲相應類型的「零」值('0000-00-00 00:00:00'、'0000-00-00'或者00000000000000)。

對於包括日期部分間割符的字符串值,若是日和月的值小於10,不須要指定兩位數。'1979-6-9'與'1979-06-09'是相同的。一樣,對於包括時間部分間割符的字符串值,若是時、分和秒的值小於10,不須要指定兩位數。'1979-10-30 1:2:3'與'1979-10-30 01:02:03'相同。

數字值應爲六、八、12或者14位長。若是一個數值是8或14位長,則假定爲YYYYMMDD或YYYYMMDDHHMMSS格式,前4位數表示年。若是數字 是6或12位長,則假定爲YYMMDD或YYMMDDHHMMSS格式,前2位數表示年。其它數字被解釋爲彷彿用零填充到了最近的長度。

指定爲非限定符字符串的值使用給定的長度進行解釋。若是字符串爲8或14字符長,前4位數表示年。不然,前2位數表示年。從左向右解釋字符串內出現的各部分,以發現年、月、日、小時、分和秒值。這說明不該使用少於6字符的字符串。例如,若是你指定'9903',認爲它表示1999年3月,MySQL將在你的表內插入一個「零」日期值。這是由於年和月值是99和03,但日部分徹底丟失,所以該值不是一個合法的日期。可是,能夠明顯指定一個零值來表明缺乏的月或日部分。例如,可使用'990300'來插入值'1999-03-00'。

在必定程度上,能夠將一個日期類型的值分配給一個不一樣的日期類型。可是,值可能會更改或丟失一些信息:

·         若是你爲一個DATETIME或TIMESTAMP對象分配一個DATE值,結果值的時間部分被設置爲'00:00:00',由於DATE值未包含時間信息。

·         若是你爲一個DATE對象分配一個DATETIME或TIMESTAMP值,結果值的時間部分被刪除,由於DATE值未包含時間信息。

·         記住儘管可使用相同的格式指定DATETIME、DATE和TIMESTAMP值,不一樣類型的值的範圍卻不一樣。例如,TIMESTAMP值不能早於1970或晚於2037。這說明一個日期,例如'1968-01-01',雖然對於DATETIME或DATE值是有效的,但對於TIMESTAMP值卻無效,若是分配給這樣一個對象將被轉換爲0。

當指定日期值時請注意某些缺陷:

·         指定爲字符串的值容許的非嚴格格式可能會欺騙。例如,值'10:11:12'因爲‘:’間割符看上去可能象時間值,但若是用於日期上下文值則被解釋爲年'2010-11-12'。值'10:45:15'被轉換爲'0000-00-00'由於'45'不是合法月。

·         在非嚴格模式,MySQL服務器只對日期的合法性進行基本檢查:年、月和日的範圍分別是1000到999九、00到12和00到31。任何包含超出這些範圍的部分的日期被轉換成'0000-00-00'。請注意仍然容許你保存非法日期,例如'2002-04-31'。要想確保不使用嚴格模式時日期有效,應檢查應用程序。

在嚴格模式,非法日期不被接受,而且不轉換。

詳細信息參見5.3.2節,「SQL服務器模式」。

·         包含兩位年值的日期會使人模糊,由於世紀不知道。MySQL使用如下規則解釋兩位年值:

o        00-69範圍的年值轉換爲2000-2069。

o        70-99範圍的年值轉換爲1970-1999。

11.3.1.1. 自MySQL 4.1以來的TIMESTAMP屬性
註釋:在舊版本的MySQL中(4.1以前),TIMESTAMP列類型的屬性在許多方面於本節所描述的大大不一樣。若是你須要對舊的TIMESTAMP數據進行轉化以便在MySQL 5.1中工做,詳情請參見MySQL 4.1 參考手冊。

TIMESTAMP列的顯示格式與DATETIME列相同。換句話說,顯示寬度固定在19字符,而且格式爲YYYY-MM-DD HH:MM:SS。

MySQL服務器也能夠以MAXDB模式運行。當服務器以該模式運行時,TIMESTAMP與DATETIME相等。也就是說,若是建立表時服務器以MAXDB模式運行,TIMESTAMP列建立爲DATETIME列。結果是,該列使用DATETIME顯示格式,有相同的值範圍,而且沒有自動對當前的日期和時間進行初始化或更新。

要想啓用MAXDB模式,在啓動服務器時使用--sql-mode=MAXDB服務器選項或在運行時經過設置全局sql_mode變量將SQL服務器模式設置爲MAXDB:

mysql> SET GLOBAL sql_mode=MAXDB;
客戶端能夠按照下面方法讓服務器爲它的鏈接以MAXDB模式運行:

mysql> SET SESSION sql_mode=MAXDB;
 

MySQL不接受在日或月列包括一個零或包含非法日期值的時間戳值。該規則的惟一例外是特殊值'0000-00-00 00:00:00'。

你能夠很是靈便地肯定何時初始化和更新TIMESTAMP和對哪些列進行初始化和更新:

·         你能夠將當前的時間戳指定爲默認值和自動更新的值。但只能選擇一個,或者二者都不選。(不可能一個列選擇一個行爲而另外一個列選擇另外一個行爲)。

·         你能夠指定哪一個TIMESTAMP列自動初始化或更新爲當前的日期和時間。再也不須要爲第1個TIMESTAMP列。

請注意下面討論所信息只適用於建立時未啓用MAXDB模式的表的TIMESTAMP列。(如上所述,MAXDB模式使列建立爲DATETIME列)。控制TIMESTAMP列的初始化和更新的規則以下所示:

·         若是一個表內的第1個TIMESTAMP列指定爲一個DEFAULT值,則不能忽略。 默認值能夠爲CURRENT_TIMESTAMP或常量日期和時間值。

·         DEFAULT NULL與第1個TIMESTAMP 列的DEFAULT CURRENT_TIMESTAMP相同。對於其它TIMESTAMP列,DEFAULT NULL被視爲DEFAULT 0。

·         表內的任何一個TIMESTAMP列能夠設置爲自動初始化爲當前時間戳和/或更新。

·         在CREATE TABLE語句中,能夠用下面的任何一種方式聲明第1個TIMESTAMP列:

o        用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP子句,列爲默認值使用當前的時間戳,而且自動更新。

o        不使用DEFAULT或ON UPDATE子句,與DEFAULT CURRENT_TIMESTAMP ON UPDATECURRENT_TIMESTAMP相同。

o        用DEFAULT CURRENT_TIMESTAMP子句不用ON UPDATE子句,列爲默認值使用當前的時間戳可是不自動更新。

o        不用DEFAULT子句但用ON UPDATE CURRENT_TIMESTAMP子句,列有默認值0並自動更新。

o        用常量DEFAULT值,列有給出的 默認值。若是列有一個ON UPDATE CURRENT_TIMESTAMP子句,它自動更新,不然不。

換句話說,你能夠爲初始值和自動更新的值使用當前的時間戳,或者其中一個使用,或者兩個皆不使用。(例如,你能夠指定ON UPDATE來啓用自動更新而不讓列自動初始化)。

·         在DEFAULT和ON UPDATE子句中可使用CURRENT_TIMESTAMP、CURRENT_TIMESTAMP()或者NOW()。它們均具備相同的效果。

兩個屬性的順序並不重要。若是一個TIMESTAMP列同時指定了DEFAULT和ON UPDATE,任何一個能夠在另外一個的前面。

例子,下面這些語句是等效的:

CREATE TABLE t (ts TIMESTAMP);
CREATE TABLE t (ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                             ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t (ts TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                             DEFAULT CURRENT_TIMESTAMP);
·         要爲TIMESTAMP列而不是第1列指定自動默認或更新,必須經過將第1個TIMESTAMP列顯式分配一個常量DEFAULT值來禁用自動初始化和更新。(例如,DEFAULT 0或DEFAULT'2003-01-01 00:00:00')。而後,對於其它TIMESTAMP列,規則與第1個TIMESTAMP列相同,例外狀況是不能忽略DEFAULT和ON UPDATE子句。若是這樣作,則不會自動進行初始化或更新。

例如:下面這些語句是等效的:

CREATE TABLE t (
    ts1 TIMESTAMP DEFAULT 0,
    ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                  ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t (
    ts1 TIMESTAMP DEFAULT 0,
    ts2 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                  DEFAULT CURRENT_TIMESTAMP);
能夠對每一個鏈接設置當前的時區,相關描述參見5.10.8節,「MySQL服務器時區支持」。TIMESTAMP值以UTC格式保存,存儲時對當前的時區進行轉換,檢索時再轉換回當前的時區。只要時區設定值爲常量,即可以獲得保存時的值。若是保存一個TIMESTAMP值,應更改時區而後檢索該值,它與你保存的值不一樣。這是由於在兩個方向的轉換中沒有使用相同的時區。當前的時區能夠用做time_zone系統變量的值。

能夠在TIMESTAMP列的定義中包括NULL屬性以容許列包含NULL值。例如:

CREATE TABLE t
(
  ts1 TIMESTAMP NULL DEFAULT NULL,
  ts2 TIMESTAMP NULL DEFAULT 0,
  ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
);
若是未指定NULL屬性,將列設置爲NULL設置則會將它設置爲當前的時間戳。請注意容許NULL值的TIMESTAMP列不會採用當前的時間戳,除非要麼其 默認值定義爲CURRENT_TIMESTAMP,或者NOW()或CURRENT_TIMESTAMP被插入到該列內。換句話說,只有使用以下定義建立,定義爲 NULL的TIMESTAMP列纔會自動更新:

CREATE TABLE t (ts NULLDEFAULT CURRENT_TIMESTAMP);
不然-也就是說,若是使用NULL而不是DEFAULT TIMESTAMP來定義TIMESTAMP列,以下所示...

CREATE TABLE t1 (ts NULL DEFAULT NULL);
CREATE TABLE t2 (ts NULL DEFAULT '0000-00-00 00:00:00');
...則必須顯式插入一個對應當前日期和時間的值。例如:

INSERT INTO t1 VALUES (NOW());
INSERT INTO t2 VALUES (CURRENT_TIMESTAMP);
11.3.2. TIME類型
MySQL以'HH:MM:SS'格式檢索和顯示TIME值(或對於大的小時值採用'HHH:MM:SS'格式)。TIME值的範圍能夠從'-838:59:59'到'838:59:59'。小時部分會所以大的緣由是TIME類型不只能夠用於表示一天的時間(必須小於24小時),還可能爲某個事件過去的時間或兩個事件之間的時間間隔(能夠大於24小時,或者甚至爲負)。

你能夠用各類格式指定TIME值:

·         'D HH:MM:SS.fraction'格式的字符串。還可使用下面任何一種「非嚴格」語法:'HH:MM:SS.fraction'、'HH:MM:SS'、'HH:MM'、'D HH:MM:SS'、'D HH:MM'、'D HH'或'SS'。這裏D表示日,能夠取0到34之間的值。請注意MySQL還不保存分數。

·         'HHMMSS'格式的沒有間割符的字符串,假定是有意義的時間。例如,'101112'被理解爲'10:11:12',但'109712'是不合法的(它有一個沒有意義的分鐘部分),將變爲'00:00:00'。

·         HHMMSS格式的數值,假定是有意義的時間。例如,101112被理解爲'10:11:12'。下面格式也能夠理解:SS、MMSS、HHMMSS、HHMMSS.fraction。請注意MySQL還不保存分數。

·         函數返回的結果,其值適合TIME上下文,例如CURRENT_TIME。

對於指定爲包括時間部分間割符的字符串的TIME值,若是時、分或者秒值小於10,則不須要指定兩位數。'8:3:2'與'08:03:02'相同。

爲TIME列分配簡寫值時應注意。沒有冒號,MySQL解釋值時假定最右邊的兩位表示秒。(MySQL解釋TIME值爲過去的時間而不是當天的時間)。例如,你可能認爲'1112'和1112表示'11:12:00'(11點過12分),但MySQL將它們解釋爲'00:11:12'(11分,12 秒)。一樣,'12'和12 被解釋爲 '00:00:12'。相反,TIME值中使用冒號則確定被看做當天的時間。也就是說,'11:12'表示'11:12:00',而不是'00:11:12'。

超出TIME範圍但合法的值被裁爲範圍最接近的端點。例如,'-850:00:00'和'850:00:00'被轉換爲'-838:59:59'和'838:59:59'。

無效TIME值被轉換爲'00:00:00'。請注意因爲'00:00:00'自己是一個合法TIME值,只從表內保存的一個'00:00:00'值還不能說出原來的值是 '00:00:00'仍是不合法的值。

11.3.3. YEAR類型
YEAR類型是一個單字節類型用於表示年。

MySQL以YYYY格式檢索和顯示YEAR值。範圍是1901到2155。

能夠指定各類格式的YEAR值:

·         四位字符串,範圍爲'1901'到'2155'。

·         四位數字,範圍爲1901到2155。

·         兩位字符串,範圍爲'00'到'99'。'00'到'69'和'70'到'99'範圍的值被轉換爲2000到2069和1970到1999範圍的YEAR值。

·         兩位整數,範圍爲1到99。1到69和70到99範圍的值被轉換爲2001到2069和1970到1999範圍的YEAR值。請注意兩位整數範圍與兩位字符串範圍稍有不一樣,由於你不能直接將零指定爲數字並將它解釋爲2000。你必須將它指定爲一個字符串'0'或'00'或它被解釋爲0000。

·         函數返回的結果,其值適合YEAR上下文,例如NOW()。

非法YEAR值被轉換爲0000。

11.3.4. Y2K事宜和日期類型
MySQL自己對於2000年(Y2K)是安全的(參見1.4.5節,「2000年兼容性」),但輸入給MySQL的值可能不安全。任何包含兩位年值的輸入都會使人模糊,由於世紀不知道。這些值必須解釋爲四位形式,由於MySQL內部使用四位來保存年。

對於DATETIME、DATE、TIMESTAMP和YEAR類型,MySQL使用如下規則解釋含模糊年值的日期:

·         00-69範圍的年值轉換爲2000-2069。

·         70-99範圍的年值轉換爲1970-1999。

請記住這些規則只是合理猜想數據值表示什麼。若是MySQL使用的啓發不能產生正確的值,你應提供包含四位年值的確切輸入。

ORDER BY能夠正確排序有兩位年的TIMESTAMP或YEAR值。

部分函數如MIN()和MAX()將TIMESTAMP或YEAR轉換爲一個數字。這說明使用有兩位年值的值,這些函數不能工做正確。在這種狀況下的修復方法是將TIMESTAMP或YEAR轉換爲四位年格式或使用MIN(DATE_ADD(TIMESTAMP,INTERVAL 0 DAYS))。

11.4. String類型
11.4.1. CHAR和VARCHAR類型
11.4.2. BINARY和VARBINARY類型
11.4.3. BLOB和TEXT類型
11.4.4. ENUM類型
11.4.5. SET類型
字符串類型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。該節描述了這些類型如何工做以及如何在查詢中使用這些類型。
11.4.1. CHAR和VARCHAR類型
CHAR和VARCHAR類型相似,但它們保存和檢索的方式不一樣。它們的最大長度和是否尾部空格被保留等方面也不一樣。在存儲或檢索過程當中不進行大小寫轉換。

CHAR和VARCHAR類型聲明的長度表示你想要保存的最大字符數。例如,CHAR(30)能夠佔用30個字符。

CHAR列的長度固定爲建立表時聲明的長度。長度能夠爲從0到255的任何值。當保存CHAR值時,在它們的右邊填充空格以達到指定的長度。當檢索到CHAR值時,尾部的空格被刪除掉。在存儲或檢索過程當中不進行大小寫轉換。

VARCHAR列中的值爲可變長字符串。長度能夠指定爲0到65,535之間的值。(VARCHAR的最大有效長度由最大行大小和使用的字符集肯定。總體最大長度是65,532字節)。

同CHAR對比,VARCHAR值保存時只保存須要的字符數,另加一個字節來記錄長度(若是列聲明的長度超過255,則使用兩個字節)。

VARCHAR值保存時不進行填充。當值保存和檢索時尾部的空格仍保留,符合標準SQL。

若是分配給CHAR或VARCHAR列的值超過列的最大長度,則對值進行裁剪以使其適合。若是被裁掉的字符不是空格,則會產生一條警告。若是裁剪非空格字符,則會形成錯誤(而不是警告)並經過使用嚴格SQL模式禁用值的插入。參見5.3.2節,「SQL服務器模式」。

下面的表顯示了將各類字符串值保存到CHAR(4)和VARCHAR(4)列後的結果,說明了CHAR和VARCHAR之間的差異:


CHAR(4)

存儲需求

VARCHAR(4)

存儲需求

''

'    '

4個字節

''

1個字節

'ab'

'ab  '

4個字節

'ab '

3個字節

'abcd'

'abcd'

4個字節

'abcd'

5個字節

'abcdefgh'

'abcd'

4個字節

'abcd'

5個字節

請注意上表中最後一行的值只適用不使用嚴格模式時;若是MySQL運行在嚴格模式,超過列長度不的值不保存,而且會出現錯誤。

從CHAR(4)和VARCHAR(4)列檢索的值並不老是相同,由於檢索時從CHAR列刪除了尾部的空格。經過下面的例子說明該差異:

mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.02 sec)
 
mysql> INSERT INTO vc VALUES ('ab  ', 'ab  ');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT CONCAT(v, '+'), CONCAT(c, '+') FROM vc;
+----------------+----------------+
| CONCAT(v, '+') | CONCAT(c, '+') |
+----------------+----------------+
| ab  +          | ab+            |
+----------------+----------------+
1 row in set (0.00 sec)
根據分配給列的字符集校對規則對CHAR和VARCHAR列中的值進行排序和比較。

請注意全部MySQL校對規則屬於PADSPACE類。這說明在MySQL中的全部CHAR和VARCHAR值比較時不須要考慮任何尾部空格。例如:

mysql> CREATE TABLE names (myname CHAR(10), yourname VARCHAR(10));
Query OK, 0 rows affected (0.09 sec)
 
mysql> INSERT INTO names VALUES ('Monty ', 'Monty ');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT myname = 'Monty  ', yourname = 'Monty  ' FROM names;
+--------------------+----------------------+
| myname = 'Monty  ' | yourname = 'Monty  ' |
+--------------------+----------------------+
|                  1 |                    1 |
+--------------------+----------------------+
1 row in set (0.00 sec)
請注意全部MySQL版本均如此,而且它不受SQL服務器模式的影響。

對於尾部填充字符被裁剪掉或比較時將它們忽視掉的情形,若是列的索引須要惟一的值,在列內插入一個只是填充字符數不一樣的值將會形成複製鍵值錯誤。

CHAR BYTE是CHAR BINARY的別名。這是爲了保證兼容性。

ASCII屬性爲CHAR列分配latin1字符集。UNICODE屬性分配ucs2字符集。

11.4.2. BINARY和VARBINARY類型
BINARY和VARBINARY類相似於CHAR和VARCHAR,不一樣的是它們包含二進制字符串而不要非二進制字符串。也就是說,它們包含字節字符串而不是字符字符串。這說明它們沒有字符集,而且排序和比較基於列值字節的數值值。

BINARY和VARBINARY容許的最大長度同樣,如同CHAR和VARCHAR,不一樣的是BINARY和VARBINARY的長度是字節長度而不是字符長度。

BINARY和VARBINARY數據類型不一樣於CHAR BINARY和VARCHAR BINARY數據類型。對於後一種類型,BINARY屬性不會將列視爲二進制字符串列。相反,它導致使用列字符集的二元 校對規則,而且列自身包含非二進制字符字符串而不是二進制字節字符串。例如CHAR(5) BINARY被視爲CHAR(5) CHARACTER SET latin1 COLLATE latin1_bin,假定默認字符集是latin1。這不一樣於BINARY(5),它保存5字節二進制字符串,沒有字符集或 校對規則。

當保存BINARY值時,在它們右邊填充值以達到指定長度。填充值是0x00(零字節)。插入值時在右側添加0x00 on,而且選擇時不刪除尾部的字節。比較時全部字節很重要,包括ORDER BY和DISTINCT操做。比較時0x00字節和空格是不一樣的,0x00<空格。

例如:對於一個BINARY(3)列,當插入時 'a' 變爲 'a \0'。'a\0'插入時變爲'a\0\0'。當選擇時兩個插入的值均不更改。

對於VARBINARY,插入時不填充字符,選擇時不裁剪字節。比較時全部字節很重要,包括ORDER BY和DISTINCT操做。比較時0x00字節和空格是不一樣的,0x00<空格。

對於尾部填充字符被裁剪掉或比較時將它們忽視掉的情形,若是列的索引須要惟一的值,在列內插入一個只是填充字符數不一樣的值將會形成複製鍵值錯誤。

若是你計劃使用這些數據類型來保存二進制數據而且須要檢索的值與保存的值徹底相同,應考慮前面所述的填充和裁剪特徵。下面的例子說明了用0x00填充的BINARY值如何影響列值比較:

mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)
 
mysql> INSERT INTO t SET c = 'a';
Query OK, 1 row affected (0.01 sec)
 
mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t;
+--------+---------+-------------+
| HEX(c) | c = 'a' | c = 'a\0\0' |
+--------+---------+-------------+
| 610000 |       0 |           1 |
+--------+---------+-------------+
1 row in set (0.09 sec)
若是檢索的值必須與指定進行存儲而沒有填充的值相同,最好使用BLOB數據類型。

建立表時,MySQL能夠默默更改BINARY或VARBINARY列的類型。參見13.1.5.1節,「沉寂的列規格變動」。

11.4.3. BLOB和TEXT類型
BLOB是一個二進制大對象,能夠容納可變數量的數據。有4種BLOB類型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它們只是可容納值的最大長度不一樣。

有4種TEXT類型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。這些對應4種BLOB類型,有相同的最大長度和存儲需求。

參見11.5節,「列類型存儲需求」。

BLOB 列被視爲二進制字符串(字節字符串)。TEXT列被視爲非二進制字符串(字符字符串)。BLOB列沒有字符集,而且排序和比較基於列值字節的數值值。TEXT列有一個字符集,而且根據字符集的 校對規則對值進行排序和比較。

在TEXT或BLOB列的存儲或檢索過程當中,不存在大小寫轉換。

當未運行在嚴格模式時,若是你爲BLOB或TEXT列分配一個超過該列類型的最大長度的值值,值被截取以保證適合。若是截掉的字符不是空格,將會產生一條警告。使用嚴格SQL模式,會產生錯誤,而且值將被拒絕而不是截取並給出警告。參見5.3.2節,「SQL服務器模式」。

在大多數方面,能夠將BLOB列視爲可以足夠大的VARBINARY列。一樣,能夠將TEXT列視爲VARCHAR列。BLOB和TEXT在如下幾個方面不一樣於VARBINARY和VARCHAR:

·         當保存或檢索BLOB和TEXT列的值時不刪除尾部空格。(這與VARBINARY和VARCHAR列相同)。

請注意比較時將用空格對TEXT進行擴充以適合比較的對象,正如CHAR和VARCHAR。

·         對於BLOB和TEXT列的索引,必須指定索引前綴的長度。對於CHAR和VARCHAR,前綴長度是可選的。參見7.4.3節,「列索引」。

·         BLOB和TEXT列不能有 默認值。

LONG和LONG VARCHAR對應MEDIUMTEXT數據類型。這是爲了保證兼容性。若是TEXT列類型使用BINARY屬性,將爲列分配列字符集的二元 校對規則。

MySQL鏈接程序/ODBC將BLOB值定義爲LONGVARBINARY,將TEXT值定義爲LONGVARCHAR。

因爲BLOB和TEXT值可能會很是長,使用它們時可能遇到一些約束:

·         當排序時只使用該列的前max_sort_length個字節。max_sort_length的 默認值是1024;該值能夠在啓動mysqld服務器時使用--max_sort_length選項進行更改。參見5.3.3節,「服務器系統變量」。

運行時增長max_sort_length的值能夠在排序或組合時使更多的字節有意義。任何客戶端能夠更改其會話max_sort_length變量的值:

mysql> SET max_sort_length = 2000;
mysql> SELECT id, comment FROM tbl_name
    -> ORDER BY comment;
當你想要使超過max_sort_length的字節有意義,對含長值的BLOB或TEXT列使用GROUP BY或ORDER BY的另外一種方式是將列值轉換爲固定長度的對象。標準方法是使用SUBSTRING函數。例如,下面的語句對comment列的2000個字節進行排序:

mysql> SELECT id, SUBSTRING(comment,1,2000) FROM tbl_name
    -> ORDER BY SUBSTRING(comment,1,2000);
·         BLOB或TEXT對象的最大大小由其類型肯定,但在客戶端和服務器之間實際能夠傳遞的最大值由可用內存數量和通訊緩存區大小肯定。你能夠經過更改max_allowed_packet變量的值更改消息緩存區的大小,但必須同時修改服務器和客戶端程序。例如,可使用 mysql和mysqldump來更改客戶端的max_allowed_packet值。參見7.5.2節,「調節服務器參數」、8.3節,「mysql:MySQL命令行工具」和8.8節,「mysqldump:數據庫備份程序」。

每一個BLOB或TEXT值分別由內部分配的對象表示。這與其它列類型造成對比,後者是當打開表時爲每1列分配存儲引擎。

11.4.4. ENUM類型
ENUM是一個字符串對象,其值來自表建立時在列規定中顯式枚舉的一列值。

在某些狀況下,ENUM值也能夠爲空字符串('')或NULL:

·         若是你將一個非法值插入ENUM(也就是說,容許的值列以外的字符串),將插入空字符串以做爲特殊錯誤值。該字符串與「普通」空字符串不一樣,該字符串有數值值0。後面有詳細討論。

·         若是將ENUM列聲明爲容許NULL,NULL值則爲該列的一個有效值,而且 默認值爲NULL。若是ENUM列被聲明爲NOT NULL,其默認值爲容許的值列的第1個元素。

每一個枚舉值有一個索引:

·         來自列規定的容許的值列中的值從1開始編號。

·         空字符串錯誤值的索引值是0。這說明你可使用下面的SELECT語句來找出分配了非法ENUM值的行:

·                mysql> SELECT * FROM tbl_name WHERE enum_col=0;
·         NULL值的索引是NULL。

例如,定義爲ENUM的列('one','two','three')能夠有下面所示任何值。還顯示了每一個值的索引:


索引

NULL

NULL

''

0

'one'

1

'two'

2

'three'

3

枚舉最多能夠有65,535個元素。

當建立表時,ENUM成員值的尾部空格將自動被刪除。

當檢索時,保存在ENUM列的值使用列定義中所使用的大小寫來顯示。請注意能夠爲ENUM列分配字符集和 校對規則。對於二進制或大小寫敏感的校對規則,當爲列分配值時應考慮大小寫。

若是在數值上下文中檢索一個ENUM值,將返回列值的索引。例如,你能夠這樣從ENUM列搜索數值值:

mysql> SELECT enum_col+0 FROM tbl_name;
若是將一個數字保存到ENUM列,數字被視爲索引,而且保存的值是該索引對應的枚舉成員。(可是,這不適合LOAD DATA,它將全部輸入視爲字符串)。不建議使用相似數字的枚舉值來定義一個ENUM列,由於這很容易引發混淆。例如,下面的列含有字符串值'0'、'1'和'2'的枚舉成員,但數值索引值爲一、2和3:

numbers ENUM('0','1','2')
根據枚舉成員在列定義中列出的順序對ENUM值進行排序。(換句話說,ENUM值根據索引編號進行排序)。例如,對於ENUM('a','b'),'a'排在'b'前面,但對於ENUM('b','a'),'b'排在'a'前面。空字符串排在非空字符串前面,而且NULL值排在全部其它枚舉值前面。要想防止意想不到的結果,按字母順序規定ENUM列。還可使用GROUP BY  CAST(col AS CHAR)或GROUP BY  CONCAT(col)來確保按照詞彙對列進行排序而不是用索引數字。

若是你想要肯定一個ENUM列的全部可能的值,使用SHOW COLUMNS FROM tbl_name LIKE enum_col,並解析輸出中第2列的ENUM定義。

11.4.5. SET類型
SET是一個字符串對象,能夠有零或多個值,其值來自表建立時規定的容許的一列值。指定包括多個SET成員的SET列值時各成員之間用逗號(‘,’)間隔開。這樣SET成員值自己不能包含逗號。

例如,指定爲SET('one', 'two') NOT NULL的列能夠有下面的任何值:

''
'one'
'two'
'one,two'
SET最多能夠有64個不一樣的成員。

當建立表時,SET成員值的尾部空格將自動被刪除。

當檢索時,保存在SET列的值使用列定義中所使用的大小寫來顯示。請注意能夠爲SET列分配字符集和 校對規則。對於二進制或大小寫敏感的校對規則,當爲列分配值時應考慮大小寫。

MySQL用數字保存SET值,所保存值的低階位對應第1個SET成員。若是在數值上下文中檢索一個SET值,檢索的值的位設置對應組成列值的SET成員。例如,你能夠這樣從一個SET列檢索數值值:

mysql> SELECT set_col+0 FROM tbl_name;
若是將一個數字保存到SET列中,數字中二進制表示中的位肯定了列值中的SET成員。對於指定爲SET('a','b','c','d')的列,成員有下面的十進制和二進制值:

SET成員

十進制值

二進制值

'a'

1

0001

'b'

2

0010

'c'

4

0100

'd'

8

1000

 

若是你爲該列分配一個值9,其二進制形式爲1001,所以第1個和第4個SET值成員'a'和'd'被選擇,結果值爲 'a,d'。

對於包含多個SET元素的值,當插入值時元素所列的順序並不重要。在值中一個給定的元素列了多少次也不重要。當之後檢索該值時,值中的每一個元素出現一次,根據表建立時指定的順序列出元素。例如,假定某個列指定爲SET('a','b','c','d'):

mysql> CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
插入值'a,d'、'd,a'、'a,d,d'、'a,d,a'和'd,a,d':

mysql> INSERT INTO myset (col) VALUES 
-> ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');
Query OK, 5 rows affected (0.01 sec)
Records: 5  Duplicates: 0  Warnings: 0
當檢索時全部這些值顯示爲 'a,d':

mysql> SELECT col FROM myset;
+------+
| col  |
+------+
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
+------+
5 rows in set (0.04 sec)
若是將SET列設置爲一個不支持的值,則該值被忽略併發出警告:

mysql> INSERT INTO myset (col) VALUES ('a,d,d,s');
Query OK, 1 row affected, 1 warning (0.03 sec)
 
mysql> SHOW WARNINGS;
+---------+------+------------------------------------------+
| Level   | Code | Message                                  |
+---------+------+------------------------------------------+
| Warning | 1265 | Data truncated for column 'col' at row 1 |
+---------+------+------------------------------------------+
1 row in set (0.04 sec)
 
mysql> SELECT col FROM myset;
+------+
| col  |
+------+
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
| a,d  |
+------+
6 rows in set (0.01 sec)
SET值按數字順序排序。NULL值排在非NULL SET值的前面。

一般狀況,可使用FIND_IN_SET()函數或LIKE操做符搜索SET值:

mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
第1個語句找出SET_col包含value set成員的行。第2個相似,但有所不一樣:它在其它地方找出set_col包含value的行,甚至是在另外一個SET成員的子字符串中。

下面的語句也是合法的:

mysql> SELECT * FROM tbl_name WHERE set_col & 1;
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
第1個語句尋找包含第1個set成員的值。第2個語句尋找一個確切匹配的值。應注意第2類的比較。將set值與'val1,val2'比較返回的結果與同'val2,val1'比較返回的結果不一樣。指定值時的順序應與在列定義中所列的順序相同。

若是想要爲SET列肯定全部可能的值,使用SHOW COLUMNS FROM tbl_name LIKE set_col並解析輸出中第2列的SET定義。

11.5. 列類型存儲需求
根據類別列出了MySQL支持的每一個列類型的存儲需求。

MyISAM表中行的最大大小爲65,534字節。每一個BLOB和TEXT列 帳戶只佔其中的5至9個字節。

若是MyISAM表包括變長列類型,記錄格式也是可變長度。當建立表時,在某些條件下,MySQL能夠將一個列從變長類型改成固定長度的類型或反之亦然。詳細信息參見13.1.5.1節,「沉寂的列規格變動」。

數值類型存儲需求

列類型

存儲需求

TINYINT

1個字節

SMALLINT

2個字節

MEDIUMINT

3個字節

INT, INTEGER

4個字節

BIGINT

8個字節

FLOAT(p)

若是0 <= p <= 24爲4個字節, 若是25 <= p <= 53爲8個字節

FLOAT

4個字節

DOUBLE [PRECISION], item REAL

8個字節

DECIMAL(M,D), NUMERIC(M,D)

變長;參見下面的討論

BIT(M)

大約(M+7)/8個字節

DECIMAL(和NUMERIC)的存儲需求與具體版本有關:

使用二進制格式將9個十進制(基於10)數壓縮爲4個字節來表示DECIMAL列值。每一個值的整數和分數部分的存儲分別肯定。每一個9位數的倍數須要4個字節,而且「剩餘的」位須要4個字節的一部分。下表給出了超出位數的存儲需求:

剩餘的

字節

位數

數目

0

0

1

1

2

1

3

2

4

2

5

3

6

3

7

4

8

4

9

4

日期和時間類型的存儲需求

列類型

存儲需求

DATE

3個字節

DATETIME

8個字節

TIMESTAMP

4個字節

TIME

3個字節

YEAR

1個字節

字符串類型的存儲需求

列類型

存儲需求

CHAR(M)

M個字節,0 <= M <= 255

VARCHAR(M)

L+1個字節,其中L <= M 且0 <= M <= 65535(參見下面的註釋)

BINARY(M)

M個字節,0 <= M <= 255

VARBINARY(M)

L+1個字節,其中L <= M 且0 <= M <= 255

TINYBLOB, TINYTEXT

L+1個字節,其中L < 28

BLOB, TEXT

L+2個字節,其中L < 216

MEDIUMBLOB, MEDIUMTEXT

L+3個字節,其中L < 224

LONGBLOB, LONGTEXT

L+4個字節,其中L < 232

ENUM('value1','value2',...)

1或2個字節,取決於枚舉值的個數(最多65,535個值)

SET('value1','value2',...)

一、二、三、4或者8個字節,取決於set成員的數目(最多64個成員)

VARCHAR、BLOB和TEXT類是變長類型。每一個類型的存儲需求取決於列值的實際長度(用前面的表中的L表示),而不是該類型的最大可能的大小。例如,VARCHAR(10)列能夠容納最大長度爲10的字符串。實際存儲需求是字符串(L)的長度,加上一個記錄字符串長度的字節。對於字符串'abcd',L是4,存儲須要5個字節。

對於CHAR、VARCHAR和TEXT類型,前面的表中的值L和M應解釋爲字符數目,而且列定義中的這些類型的長度表示字符數目。例如,要想保存一個TINYTEXT值須要L字符+ 1個字節。

要想計算用於保存具體CHAR、VARCHAR或者TEXT列值的字節數,須要考慮該列使用的字符集。在具體狀況中,當使用Unicode時,必須記住全部Unicode字符使用相同的字節數。爲了細分用於不一樣類Unicode字符使用的存儲,參見10.5節,「Unicode支持」。

註釋:VARCHAR列的有效最大長度爲65,532字符。

NDBCLUSTER引擎只支持固定寬度的列。這說明MySQL簇中的表中的VARCHAR列的行爲如同類型CHAR(不一樣的是每一個記錄仍然有一個額外字節空間)。例如,在Cluster表中,聲明爲VARCHAR(100)的列中的每一個記錄存儲時將佔用101個字節,不管實際存儲的記錄中的字符串的長度爲多少。

BLOB和TEXT類須要 一、二、3或者4個字節來記錄列值的長度,取決於該類的最大可能的長度。參見11.4.3節,「BLOB和TEXT類型」。

在NDB Cluster存儲引擎中,TEXT和BLOB列的實施是不一樣的,其中TEXT列中的每一個記錄由兩個單獨部分組成。一個是固定大小(256字節),而且實際上保存在原表中。另外一個包括超出256字節的任何數據,保存在隱含的表中。第2個表中的記錄老是2,000字節長。這說明若是size<= 256,TEXT列的大小爲256(其中size表示記錄的大小);不然,大小是256 +size+(2000–(size–256) 00)。

ENUM對象的大小由不一樣的枚舉值的數目肯定。枚舉用一個字節,能夠有255個可能的值。當枚舉的值位於256和65,535之間時,用兩個字節。參見11.4.4節,「ENUM類型」。

SET對象的大小由不一樣的set成員的數量肯定。若是set大小是N,對象佔(N+7)/8個字節,四捨五入到一、二、三、4或者8個字節。SET最多能夠有64個成員。參見11.4.5節,「SET類型」。

11.6. 選擇正確的列類型
爲了優化存儲,在任何狀況下均應使用最精確的類型。例如,若是列的值的範圍爲從1到99999,若使用整數,則MEDIUMINT UNSIGNED是好的類型。在全部能夠表示該列值的類型中,該類型使用的存儲最少。

用精度爲65位十進制數(基於10)對DECIMAL 列進行全部基本計算(+、-、*、/)。參見11.1.1節,「數值類型概述」。

使用雙精度操做對DECIMAL值進行計算。若是準確度不是過重要或若是速度爲最高優先級,DOUBLE類型即足夠了。爲了達到高精度,能夠轉換到保存在BIGINT中的定點類型。這樣能夠用64位整數進行全部計算,根據須要將結果轉換回浮點值。

11.7. 使用來自其餘數據庫引擎的列類型
爲了使用由其它賣方編寫的SQL執行代碼,MySQL按照下表所示對列類型進行映射。經過這些映射,能夠很容易地從其它數據庫引擎將表定義導入到MySQL中:

其它賣方類型

MySQL類型

BOOL,

TINYINT

BOOLEAN

TINYINT

CHAR VARYING(M)

VARCHAR(M)

DEC

DECIMAL

FIXED

DECIMAL

FLOAT4

FLOAT

FLOAT8

DOUBLE

INT1

TINYINT

INT2

SMALLINT

INT3

MEDIUMINT

INT4

INT

INT8

BIGINT

LONG VARBINARY

MEDIUMBLOB

LONG VARCHAR

MEDIUMTEXT

LONG

MEDIUMTEXT

MIDDLEINT

MEDIUMINT

NUMERIC

DECIMAL

在建立表時對列類型進行映射,而後原來的類型定義被丟棄。若是你使用其它賣方的類型建立一個表,而後執行DESCRIBE tbl_name語句,MySQL使用等效的MySQL類型來報告表的結構。例如:

mysql> CREATE TABLE t (a BOOL, b FLOAT8, c LONG, d NUMERIC);
Query OK, 0 rows affected (0.08 sec)
 
mysql> DESCRIBE t;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a     | tinyint(1)    | YES  |     | NULL    |       |
| b     | double        | YES  |     | NULL    |       |
| c     | mediumtext    | YES  |     | NULL    |       |
| d     | decimal(10,0) | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
這是MySQL參考手冊的翻譯版本,關於MySQL參考手冊,請訪問dev.mysql.com。 原始參考手冊爲英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。
相關文章
相關標籤/搜索