7.3.5 數字類型


MySQL支持所有的ANSI/ISO SQL92的數字類型。這些類型包括準確數字的數據類型(NUMERIC, DECIMAL, INTEGER,和SMALLINT),也包括近似數字的數據類型(FLOAT, REAL,和DOUBLE PRECISION)。關鍵詞INTINTEGER的一個同義詞,而關鍵詞DECDECIMAL一個同義詞。

NUMERICDECIMAL類型被MySQL實現為同樣的類型,這在SQL92標準允許。他們被用於保存值,該值的準確精度是極其重要的值,例如與金錢有關的數據。當聲明一個類是這些類型之一時,精度和規模的能被(並且通常是)指定﹔例如:

salary DECIMAL(9,2) 

在這個例子中,9(precision)代表將被用於存儲值的總的小數位數,而2(scale)代表將被用於存儲小數點後的位數。因此,在這種情況下,能被存儲在salary列中的值的範圍是從-9999999.999999999.99。在ANSI/ISO SQL92中,句法DECIMAL(p)等價於DECIMAL(p,0)。同樣,句法DECIMAL等價於DECIMAL(p,0),這裡實現被允許決定值pMySQL當前不支持DECIMAL/NUMERIC數據類型的這些變種形式的任一種。這一般說來不是一個嚴重的問題,因為這些類型的主要益處得自於明顯地控制精度和規模的能力。

DECIMALNUMERIC值作為字符串存儲,而不是作為二進制浮點數,以便保存那些值的小數精度。一個字符用於值的每一位、小數點(如果scale>0)和“-”符號(對於負值)。如果scale是0,DECIMALNUMERIC值不包含小數點或小數部分。

DECIMALNUMERIC值得最大的範圍與DOUBLE一樣,但是對於一個給定的DECIMALNUMERIC列,實際的範圍可由制由給定列的precisionscale限制。當這樣的列賦給了小數點後面的位超過指定scale所允許的位的值,該值根據scale四舍五入。當一個DECIMALNUMERIC列被賦給了其大小超過指定(或缺省的)precisionscale隱含的範圍的值,MySQL存儲表示那個範圍的相應的端點值。

作為對ANSI/ISO SQL92標準的擴展,MySQL也支持上表所列的整型類型TINYINT、MEDIUMINT和BIGINT。另一個擴展是MySQL支持可選地指定一個整型值顯示的寬度,用括號跟在基本關鍵詞之後(例如,INT(4))。這個可選的寬度指定被用於其寬度小於列指定寬度的值得左填補顯示,但是不限制能在列中被存儲的值的範圍,也不限制值將被顯示的位數,其寬度超過列指定的寬度。當與可選的擴展屬性ZEROFILL一起使用時,缺省的空格填補用零代替。例如,對於聲明為INT(5) ZEROFILL的列,一個為4的值作為00004被檢索。注意,如果你在一個整型列存儲超過顯示寬度的更大值,當MySQL對於某些復雜的聯結(join)生成臨時表時,你可能會遇到問題,因為在這些情況下,MySQL相信數據確實適合原來的列寬度。

所有的整型類型可以有一個可選(非標準的)屬性UNSIGNED。當你想要在列中僅允許正數並且你需要一個稍大一點的列範圍,可以使用無符號值。

FLOAT類型被用來標示近似數字的數據類型。ANSI/ISO SQL92標準允許一個可選的精度說明(但不是指數的範圍),跟在關鍵詞FLOAT後面的括號內位數。MySQL實現也支持這個可選的精度說明。當關鍵詞FLOAT被用於一個列類型而沒有精度說明時,MySQL使用4個字節存儲值。一個變種的句法也被支持,在FLOAT關鍵詞後面的括號給出2個數字。用這個選項,第一個數字繼續表示在字節計算的值存儲需求,而第二個數字指定要被存儲的和顯示跟隨小數點後的位數(就像DECIMALNUMERIC)。當MySQL要求為這樣一個列,一個小數點後的小數位超過列指定的值,存儲值時,該值被四舍五入,去掉額外的位。

REALDOUBLE PRECISION類型不接受精度說明。作為對 ANSI/ISO SQL92 標準的擴展,MySQL識別出DOUBLE作為DOUBLE PRECISION類型的一個同義詞。與REAL精度比用於DOUBLE PRECISION的更小的標準要求相反,MySQL實現了兩種,作為8字節雙精度浮點值(當運行不是“Ansi模式”時)。為了最大的移植性,近似數字的數據值的存儲所需代碼應該使用沒有精度或小數位數說明的FLOATDOUBLE PRECISION

當要求在數字的列存儲超出該列類型允許的範圍的值時,MySQL剪切該值到範圍內的正確端點值並且存儲剪切後的結果值。

例如,一個INT列的範圍是-21474836482147483647。如果你試圖插入-9999999999到一個INT列中,值被剪切到範圍的低部端點,並存儲-2147483648。同樣,如果你試圖插入99999999992147483647被存儲。

如果INT列是UNSIGNED,列的範圍的大小是相同的,但是它的端點移到了04294967295。如果你試圖存儲-99999999999999999999,在列被存儲的值變為04294967296

對於ALTER TABLELOAD DATA INFILEUPDATE和多行INSERT語句,由於剪切所發生的變換作為“警告”被報告。

7.3.6 日期和時間類型

日期和時間類型是DATETIMEDATETIMESTAMPTIMEYEAR。這些的每一個都有合法值的一個範圍,而“零”當你指定確實不合法的值時被使用。注意,MySQL允許你存儲某個“不嚴格地”合法的日期值,例如1999-11-31,原因我們認為它是應用程序的責任來處理日期檢查,而不是SQL服務器。為了使日期檢查更“快”,MySQL僅檢查月份在0-12的範圍,天在0-31的範圍。上述範圍這樣被定義是因為MySQL允許你在一個DATEDATETIME列中存儲日期,這裡的天或月是零。這對存儲你不知道準確的日期的一個生日的應用程序來說是極其有用的,在這種情況下,你簡單地存儲日期像1999-00-001999-01-00。(當然你不能期望從函數如DATE_SUB()DATE_ADD()得到類似以這些日期的正確值)。

當用日期和時間工作時,這裡是的一些要記住的一般考慮:

7.3.6.1 Y2K問題和日期類型

MySQL本身Y2K安全的(見1.6 2000年一致性),但是呈交給MySQL的輸入值可能不是。一個包含2位年份值的任何輸入是由二義性的,因為世紀是未知的。這樣的值必須被解釋成4位形式,因為MySQL內部使用4位存儲年份。

對於DATETIME, DATE, TIMESTAMPYEAR類型,MySQL使用下列規則的解釋二義性的年份值:

記得這些規則僅僅提供對於你數據的含義的合理猜測。如果MySQL使用的啟發規則不產生正確的值,你應該提供無二義的包含4位年值的輸入。

7.3.6.2 DATETIME, DATETIMESTAMP類型

DATETIME, DATETIMESTAMP類型是相關的。本節描述他們的特徵,他們是如何類似的而又不同的。

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列類型提供一種類型,你可以使用它自動地用當前的日期和時間標記INSERTUPDATE的操作。如果你有多個TIMESTAMP列,只有第一個自動更新。

自動更新第一個TIMESTAMP列在下列任何條件下發生:

除第一個以外的TIMESTAMP列也可以設置到當前的日期和時間,只要將列設為NULL,或NOW()

通過明確地設置希望的值,你可以設置任何TIMESTAMP列為不同於當前日期和時間的值,即使對第一個TIMESTAMP列也是這樣。例如,如果,當你創建一個行時,你想要一個TIMESTAMP被設置到當前的日期和時間,但在以後無論何時行被更新時都不改變,你可以使用這個屬性:

另一方面,你可能發現,當行被創建並且遠離隨後的更改時,很容易用一個你用NOW()初始化的DATETIME列。

TIMESTAMP值可以從1970的某時的開始一直到2037年,精度為一秒,其值作為數字顯示。

MySQL檢索並且顯示TIMESTAMP值取決於顯示尺寸的格式如下表。“完整”TIMESTAMP格式是14位,但是TIMESTAMP列可以用更短的顯示尺寸創造:

列類型

顯示格式

TIMESTAMP(14)

YYYYMMDDHHMMSS

TIMESTAMP(12)

YYMMDDHHMMSS

TIMESTAMP(10)

YYMMDDHHMM

TIMESTAMP(8)

YYYYMMDD

TIMESTAMP(6)

YYMMDD

TIMESTAMP(4)

YYMM

TIMESTAMP(2)

YY

所有的TIMESTAMP列都有同樣的存儲大小,不考慮顯示尺寸。最常見的顯示尺寸是6、8、12、和14。你可以在表創建時間指定一個任意的顯示尺寸,但是值0或比14大被強制到14。在從1∼13範圍的奇數值尺寸被強制為下一個更大的偶數。

使用一個常用的格式集的任何一個,你可以指定DATETIMEDATETIMESTAMP值:

不合法DATETIME, DATETIMESTAMP值被變換到適當類型的“零”值('0000-00-00 00:00:00', '0000-00-00'00000000000000)。

對於包括的日期部分分隔符的指定為字符串的值,不必要為小於10的月或天的值指定2位數字,'1979-6-9''1979-06-09'是一樣的。同樣, 對於包括的時間部分分隔符的指定為字符串的值,不必為小於10的小時、月或秒指定2位數字,'1979-10-30 1:2:3''1979-10-30 01:02:03'是一樣的。

指定為數字應該是6、8、12或14位長。如果數字是8或14位長,它被假定以YYYYMMDDYYYYMMDDHHMMSS格式並且年份由頭4位數字給出。如果數字是6或12位長,它被假定是以YYMMDDYYMMDDHHMMSS格式且年份由頭2位數字給出。不是這些長度之一的數字通過填補前頭的零到最接近的長度來解釋。

指定為無分隔符的字符串用它們給定的長度來解釋。如果字符串長度是8或14個字符,年份被假定頭4個字符給出,否則年份被假定由頭2個字符給出。對於字符串中呈現的多個部分,字符串從左到右邊被解釋,以找出年、月、日、小時、分鐘和秒值,這意味著,你不應該使用少於 6 個字符的字符串。例如,如果你指定'9903',認為將代表1999年3月,你會發現MySQL把一個“零”日期插入到你的表中,這是因為年份和月份值9903,但是日期部分丟失(零),因此該值不是一個合法的日期。

TIMESTAMP列使用被指定的值的完整精度的存儲合法的值,不考慮顯示大小。這有幾個含意:

在某種程度上,你可以把一種日期類型的值賦給一個不同的日期類型的對像。然而,這可能值有一些改變或信息的損失:

當指定日期值時,當心某些缺陷:

7.3.6.3 TIME類型

MySQL檢索並以'HH:MM:SS'格式顯示TIME值(或對大小時值,'HHH:MM:SS'格式)。TIME值的範圍可以從'-838:59:59''838:59:59'。小時部分可能很大的的原因是TIME類型不僅可以被使用在表示一天的時間(它必須是不到24個小時),而且用在表示在2個事件之間經過的時間或時間間隔(它可以是比24個小時大些,或甚至是負值)。

你能用多中格式指定TIME值:

對於作為包括一個時間分隔符的字符串被指定的TIME值,不必為小於10的小時、分鐘或秒值指定2位數字,'8:3:2''08:03:02'是一樣的。

將“短的”TIME值賦值給一個TIME行列是要格外小心。MySQL使用最右位代表秒的假設來解釋值。(MySQLTIME值解釋為經過的時間,而非作為一天的時間 )例如,你可能想到'11:12''1112'1112意味著'11:12:00'(11點12分),但是MySQL解釋他們為'00:11:12'(11分12秒)。同樣,'12'12被解釋為'00:00: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'或它是否是不合法的。

7.3.6.4 YEAR類型

YEAR類型是一個 1 字節類型用於表示年份。

MySQL檢索並且以YYYY格式顯示YEAR值,其範圍是19012155

你能用多種格式指定YEAR值:

不合法YEAR值被變換到0000

7.3.7 字符串類型

字符串類型是CHARVARCHARBLOBTEXTENUMSET

7.3.7.1 CHARVARCHAR類型

CHARVARCHAR類型是類似的,但是在他們被存儲和檢索的方式不同。

一個CHAR列的長度被修正為在你創造表時你所聲明的長度。長度可以是1和255之間的任何值。(在MySQL 3.23中,CHAR長度可以是0∼255。) 當CHAR值被存儲時,他們被用空格在右邊填補到指定的長度。當CHAR值被檢索時,拖後的空格被刪去。

VARCHAR列中的值是變長字符串。你可以聲明一個VARCHAR列是在1和255之間的任何長度,就像對CHAR列。然而,與CHAR相反,VARCHAR值只存儲所需的字符,外加一個字節記錄長度,值不被填補﹔相反,當值被存儲時,拖後的空格被刪去。(這個空格刪除不同於ANSI SQL規范。)

如果你把一個超過列最大長度的值賦給一個CHARVARCHAR列,值被截斷以適合它。

下表顯示了兩種類型的列的不同,通過演示存儲變長字符串值到CHAR(4)VARCHAR(4)列:

CHAR(4)

存儲需求

VARCHAR(4)

存儲需求

''

' '

4 個字節

''

1 字節

'ab'

'ab '

4 個字節

'ab'

3 個字節

'abcd'

'abcd'

4 個字節

'abcd'

5 個字節

'abcdefgh'

'abcd'

4 個字節

'abcd'

5 個字節

CHAR(4)VARCHAR(4)列檢索的值在每種情況下都是一樣的,因為拖後的空格從檢索的CHAR列上被刪除。

CHARVARCHAR列中存儲和比較值是以大小寫不區分的方式進行的,除非當桌子被創建時,BINARY屬性被指定。BINARY屬性意味著該列的值根據MySQL服務器正在運行的機器的ASCII順序以大小寫區分的方式存儲和比較。

BINARY屬性是“粘性”的。這意味著,如果標記了BINARY的列用於一個表達式中,整個的表達式作為一個BINARY值被比較。

MySQL在表創建時可以隱含地改變一個CHARVARCHAR列的類型。見7.7.1 隱含的的列說明改變

7.3.7.2 BLOBTEXT類型

一個BLOB是一個能保存可變數量的數據的二進制的大對像。4個BLOB類型TINYBLOBBLOBMEDIUMBLOBLONGBLOB僅僅在他們能保存值的最大長度方面有所不同。見7.3.1 列類型存儲需求

4個TEXT類型TINYTEXTTEXTMEDIUMTEXTLONGTEXT對應於4個BLOB類型,並且有同樣的最大長度和存儲需求。在BLOBTEXT類型之間的唯一差別是對BLOB值的排序和比較以大小寫敏感方式執行,而對TEXT值是大小寫不敏感的。換句話說,一個TEXT是一個大小寫不敏感的BLOB

如果你把一個超過列類型最大長度的值賦給一個BLOBTEXT列,值被截斷以適合它。

在大多數方面,你可以認為一個TEXT行列是你所希望大的一個VARCHAR列。同樣,你可以認為一個BLOB列是一個VARCHAR BINARY列。差別是:

MyODBC定義BLOBLONGVARBINARYTEXT值為LONGVARCHAR

因為BLOBTEXT值可以是非常長的,當使用他們時,你可能遇到一些限制:

注意,每個BLOBTEXT值內部由一個獨立分配的對像表示。這與所有的其他列類型相反,它們是在打開表時,按列被分配一次存儲。

7.3.7.3 ENUM類型

一個ENUM是一個字符對像,其值通常從一個在表創建時明確被列舉的允許值的一張表中選擇。

在下列的某個情形下,值也可以空字符串("")或NULL

每枚舉值有一個編號:

例如,指定為ENUM("one", "two", "three")的列可以有顯示在下面的值的任何一個。每個值的編號也被顯示:

編號

NULL

NULL

""

0

"one"

1

"two"

2

"three"

3

枚舉可以有最大65535個成員。

當你把值賦給一個ENUM列時,字母的大小寫是無關緊要的。然而,以後從列中檢索的值大小寫匹配在表創建時用來指定允許值的值的大小寫。

如果你在一個數字的上下文環境中檢索一個ENUM,列值的編號被返回。如果你存儲一個數字到一個ENUM中,數字被當作一個標號,並且存儲的值是該編號的枚舉成員。

ENUM值根據列說明列舉的枚舉成員的次序被排序。(換句話說,ENUM值根據他們的編號數字被排序) 例如,對ENUM("a", "b"),"a"排在"b"前面,但是對ENUM("b", "a"),"b"排在"a"前面。空字符串排序非空字符串之前,並且NULL排在所有其他枚舉值之前。

如果你想要得到一個ENUM列的所有可能的值,你應該使用:SHOW COLUMNS FROM table_name LIKE enum_column_name並且分析在第二列的ENUM定義。

7.3.7.4 SET類型

一個SET是可以有零或多個值的一個字符串對像,其每一個必須從表創建造被指定了的允許值的一張列表中被選擇。由多個集合成員組成的SET列通過由由逗號分隔(“,”)的成員被指定,其推論是該SET成員值不能包含逗號本身。

例如, 一個指定為SET("one", "two") NOT NULL的列可以有這些值的任何一個:

"" 
"one" 
"two" 
"one,two"

一個SET能有最多64個不同的成員。 

MySQL用數字值存儲SET值,存儲值的低階位對應於第一個集合成員。如果你在數字上下文中檢索一個SET值,檢索的值把位設置位對應組成列值的集合成員。如果一個數字被存儲進一個SET列,在數字的二進制表示中設置的位決定了在列中的集合成員。假定一個列被指定為SET("a","b","c","d"),那麼成員有下列位值:

SET 成員

十進制的值

二進制的值

a

1

0001

b

2

0010

c

4

0100

d

8

1000

如果你給該列賦值9,即二進制的1001,這樣第一個和第四個SET值成員"a""d"被選擇並且結果值是"a,d"

對於包含超過一個SET成員的值,當你插入值時,無所謂以什麼順序列舉值,也無所謂給定的值列舉了多少次。當以後檢索值時,在值中的每個成員將出現一次,根據他們在表創建時被指定的順序列出成員。例如,如果列指定為SET("a","b","c","d"),那麼"a,d""d,a""d,a,a,d,d"在檢索時將均作為"a,d"出現。

SET值以數字次序被排序。NULL指排在非NULL SET值之前。

通常,你使用LIKE操作符或FIND_IN_SET()函數執行在一個SET上的一個SELECT

mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;

但是下列也會工作:

mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
mysql> SELECT * FROM tbl_name WHERE set_col & 1;

這些語句的第一個語句尋找一個精確的匹配。第二個尋找包含第一個集合成員的值。

如果你想要得到一個SET列的所有可能的值,你應該使用:SHOW COLUMNS FROM table_name LIKE set_column_name並且分析在第二列的SET定義。

7.3.8 為列選擇正確的類型

為了最有效地使用存儲空間,試著在所有的情況下使用最精確的類型。例如,如果一個整數列被用於在之間199999的值, MEDIUMINT UNSIGNED是最好的類型。

貨幣值的精確表示是一個常見的問題。在MySQL,你應該使用DECIMAL類型,它作為一個字符串被存儲,不會發生精確性的損失。如果精確性不是太重要,DOUBLE類型也是足夠好的。

對高精度,你總是能變換到以一個BIGINT存儲的定點類型。這允許你用整數做所有的計算,並且僅在必要時將結果轉換回浮點值。見10.6 選擇一個表類型