九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
MySQL數(shù)據(jù)庫技術(shù)(08)
數(shù)據(jù)庫中的每個表都是由一個或多個列構(gòu)成的。在用C R E ATE TABLE 語句創(chuàng)建一個表時,要為每列指定一個類型。列的類型比數(shù)據(jù)類型更為特殊,它僅僅是如“數(shù)”或“串”這樣的通用類型。列的類型精確地描述了給定表列可能包含的值的種類,如SMALLINT 或VA R C H A R ( 3 2 )。
MySQL 的列類型是一種手段,通過這種手段可以描述一個表列包含什么類型的值,這又決定了MySQL 怎樣處理這些值。例如,數(shù)值值既可用數(shù)值也可用串的列類型來存放,但是根據(jù)存放這些值的類型, MySQL 對它們的處理將會有些不同。每種列類型都有幾個特性如下:
■ 其中可以存放什么類型的值。
■ 值要占據(jù)多少空間,以及該值是否是定長的(所有值占相同數(shù)量的空間)或可變長的(所占空間量依賴于所存儲的值)。
■ 該類型的值怎樣比較和存儲。
■ 此類型是否允許NULL 值。
■ 此類型是否可以索引。
我們將簡要地考察一下M y S Q L列類型以獲得一個總的概念,然后更詳細(xì)地討論描述每種列類型的屬性。
2.2.1 列類型概述
MySQL 為除NULL 值以外的所有通用數(shù)據(jù)類型的值都提供了列類型。在列是否能夠包含NULL 值被視為一種類型屬性的意義上,可認(rèn)為所有類型都包含N U L L屬性。M y S Q L有整數(shù)和浮點(diǎn)數(shù)值的列類型,如表2 - 2所示。整數(shù)列類型可以有符號也可無符號。有一種特殊的屬性允許整數(shù)列值自動生成,這對需要唯一序列或標(biāo)識號的應(yīng)用系統(tǒng)來說是非常有用的。
MySQL 串列類型如表2 - 3所示。串可以存放任何內(nèi)容,即使是像圖像或聲音這樣的絕對二進(jìn)制數(shù)據(jù)也可以存放。串在進(jìn)行比較時可以設(shè)定是否區(qū)分大小寫。此外,可對串進(jìn)行模式匹配(實(shí)際上,在MySQL 中可以在任意列類型上進(jìn)行模式匹配,但最經(jīng)常進(jìn)行模式匹配還是在串類型上)
日期與時間列類型在表2 - 4中示出。對于臨時值, MySQL 提供了日期(有或沒有時間)、時間和時間戳(一種允許跟蹤對記錄何時進(jìn)行最后更改的特殊類型)的類型。而且還提供了一種在不需要完整的日期時有效地表示年份的類型。
要創(chuàng)建一個表,應(yīng)使用C R E ATE TABLE 語句并指定構(gòu)成表列的列表。每個列都有一個名字和類型,以及與每個類型相關(guān)的各種屬性。下面是創(chuàng)建具有三個分別名為f、c 和i 的列的表my_table 的例子:
定義一個列的語法如下:
其中列名由col_name 給出。列名可最多包含64 個字符,字符包括字母、數(shù)字、下劃線及美元符號。列名可以名字中合法的任何符號(包括數(shù)字)開頭。但列名不能完全由數(shù)字組成,因?yàn)槟菢涌赡苁蛊渑c數(shù)據(jù)分不開。M y S Q L保留諸如S E L E C T、DELETE 和C R E ATE 這樣的詞,這些詞不能用做列名。但是函數(shù)名(如POS 和M I N)是可以使用的。
列類型col_type 表示列可存儲的特定值。列類型說明符還能表示存放在列中的值的最大長度。對于某些類型,可用一個數(shù)值明確地說明其長度。而另外一些值,其長度由類型名蘊(yùn)含。例如,CHAR(10) 明確指定了10 個字符的長度。而TINYBLOB 值隱含最大長度為2 5 5個字符。有的類型說明符允許指定最大的顯示寬度(即顯示值時使用多少個字符)。浮點(diǎn)類型允許指定小數(shù)位數(shù),所以能控制浮點(diǎn)數(shù)的精度值為多少。
可以在列類型之后指定可選的類型說明屬性,以及指定更多的常見屬性。屬性起修飾類型的作用,并更改其處理列值的方式,屬性有以下類型:
■ 專用屬性用于指定列。例如,UNSIGNED 屬性只針對整型,而B I N A RY 屬性只用于CHAR 和VA R C H A R。
■ 通用屬性除少數(shù)列之外可用于任意列??梢灾付∟ULL 或NOT NULL 以表示某個列是否能夠存放N U L L。還可以用D E FA U LT def_value 來表示在創(chuàng)建一個新行但未明確給出該列的值時,該列可賦予值d e f _ v a l u e。def_value 必須為一個常量;它不能是表達(dá)式,也不能引用其他列。不能對BLOB 或TEXT 列指定缺省值。
如果想給出多個列的專用屬性,可按任意順序指定它們,只要它們跟在列類型之后、通用屬性之前即可。類似地,如果需要給出多個通用屬性,也可按任意順序給出它們,只要將它們放在列類型和可能給出的列專用屬性之后即可。本節(jié)其余部分討論每個MySQL 的列類型,給出定義類型和描述它們的屬性的語法,諸如取值范圍和存儲需求等。類型說明如在C R E ATE TABLE 語句中那樣給出??蛇x的信息由方括號([ ])給出。如,語MEDIUMINT[(M)] 表示最大顯示寬度(指定為M)是可選的。另一方面,對于C H A R ( M ),無方括號表示的(M) 是必須的。
2.2.2 數(shù)值列類型
MySQL 的數(shù)值列類型有兩種:
■ 整型。用于無小數(shù)部分的數(shù),如1、4 3、- 3、0 或- 7 9 8 4 3 2??蓪φ龜?shù)表示的數(shù)據(jù)使用整數(shù)列,如磅的近似數(shù)、英寸的近似數(shù),銀河系行星的數(shù)目、家族人數(shù)或一個盤子里的細(xì)菌數(shù)等。
■ 浮點(diǎn)數(shù)。用于可能具有小數(shù)部分的數(shù),如3 . 1 4 1 5 9、- . 0 0 2 7 3、- 4 . 7 8、或3 9 . 3 E + 4??蓪⒏↑c(diǎn)數(shù)列類型用于有小數(shù)點(diǎn)部分或極大、極小的數(shù)??赡軙硎緸楦↑c(diǎn)數(shù)的值有農(nóng)作物平均產(chǎn)量、距離、錢數(shù)(如物品價格或工資)、失業(yè)率或股票價格等等。整型值也可
以賦予浮點(diǎn)列,這時將它們表示為小數(shù)部分為零的浮點(diǎn)值。每種數(shù)值類型的名稱和取值范圍如表2 - 5所示。各種類型值所需的存儲量如表2-6 所示。
CREATE TABLE 語句
本章中例子中大量使用了C R E ATE TABLE 語句。您應(yīng)該對此語句相當(dāng)熟悉,因?yàn)槲覀冊诘?章中的教程部分使用過它。關(guān)于C R E ATE TABLE 語句也可參閱附錄D。
MySQL 提供了五種整型: T I N Y I N T、S M A L L I N T、M E D I U M I N T、INT 和B I G I N T。I N T 為I N T E G E R的縮寫。這些類型在可表示的取值范圍上是不同的。整數(shù)列可定義為UNSIGNED 從而禁用負(fù)值;這使列的取值范圍為0 以上。各種類型的存儲量需求也是不同的。
取值范圍較大的類型所需的存儲量較大。
MySQL 提供三種浮點(diǎn)類型: F L O AT、DOUBLE 和D E C I M A L。與整型不同,浮點(diǎn)類型不能是UNSIGNED 的,其取值范圍也與整型不同,這種不同不僅在于這些類型有最大值,而且還有最小非零值。最小值提供了相應(yīng)類型精度的一種度量,這對于記錄科學(xué)數(shù)據(jù)來說是非常重要的(當(dāng)然,也有負(fù)的最大和最小值)。
DOUBLE PRECISION[(M, D)] 和REAL[(M, D)] 為DOUBLE[(M, D)] 的同義詞。而NUMERIC(M, D) 為DECIMAL(M, D) 的同義詞。F L O AT(4) 和F L O AT(8) 是為了與ODBC 兼容而提供的。在MySQL 3.23 以前,它們?yōu)镕 L O AT(10, 2) 和DOUBLE(16, 4) 的同義詞。自MySQL 3.23 以來,F(xiàn) L O AT(4) 和F L O AT(8) 各不相同,下面還要介紹。
在選擇了某種數(shù)值類型時,應(yīng)該考慮所要表示的值的范圍,只需選擇能覆蓋要取值的范圍的最小類型即可。選擇較大類型會對空間造成浪費(fèi),使表不必要地增大,處理起來沒有選擇較小類型那樣有效。對于整型值,如果數(shù)據(jù)取值范圍較小,如人員年齡或兄弟姐妹數(shù),則TINYINT 最合適。MEDIUMINT 能夠表示數(shù)百萬的值并且可用于更多類型的值,但存儲代價較大。BIGINT 在全部整型中取值范圍最大,而且需要的存儲空間是表示范圍次大的整型I N T類型的兩倍,因此只在確實(shí)需要時才用。對于浮點(diǎn)值, D O U B L E占用F L O AT 的兩倍空間。除非特別需要高精度或范圍極大的值,一般應(yīng)使用只用一半存儲代價的F L O AT 型來表示數(shù)據(jù)。
在定義整型列時,可以指定可選的顯示尺寸M。如果這樣,M 應(yīng)該是一個1 到255 的整數(shù)。它表示用來顯示列中值的字符數(shù)。例如, MEDIUMINT(4) 指定了一個具有4 個字符顯示寬度的MEDIUMINT 列。如果定義了一個沒有明確寬度的整數(shù)列,將會自動分配給它一個缺省的寬度。缺省值為每種類型的“最長”值的長度。如果某個特定值的可打印表示需要不止M 個字符,則顯示完全的值;不會將值截?cái)嘁赃m合M 個字符。對每種浮點(diǎn)類型,可指定一個最大的顯示尺寸M 和小數(shù)位數(shù)D。M 的值應(yīng)該取1 到2 5 5。D 的值可為0 到3 0,但是不應(yīng)大于M - 2。(如果熟悉ODBC 術(shù)語,就會知道M 和D 對應(yīng)于
ODBC 概念的“精度”和“小數(shù)點(diǎn)位數(shù)”)M 和D 對F L O AT 和DOUBLE 都是可選的,但對于DECIMAL 是必須的。在選項(xiàng)M 和D時,如果省略了它們,則使用缺省值。下面的語句創(chuàng)建了一個表,它說明了數(shù)值列類型的M 和D 的缺省值(其中不包括D E C I M A L,因?yàn)镸 和D 對這種類型不是可選的):
如果在創(chuàng)建表之后使用DESCRIBE my_table 語句,則輸出的Field 和Type 列如下所示(注意,如果用MySQL 的3.23 以前的版本運(yùn)行這個查詢,則有一個小故障, 即BIGINT 的顯示寬度將是21 而不是2 0。):
每一個數(shù)字列都具有一個由列類型所決定的取值范圍。如果打算插入一個不在列范圍內(nèi)的值,將會進(jìn)行截?。篗ySQL 將剪裁該值為取值范圍的邊界值并使用這個結(jié)果。在檢索時不進(jìn)行值的剪裁。
值的剪裁根據(jù)列類型的范圍而不是顯示寬度進(jìn)行。例如,一個SMALLINT(3) 列顯示寬度為3 而取值范圍為-32768 到3 2 7 6 7。值12345 比顯示寬度大,但在該列的取值范圍內(nèi),因此它可以插入而不用剪裁并且作為12345 檢索。值99999 超出了取值范圍,因此在插入時被剪裁為3 2 7 6 7。以后在檢索中將以值3 2 7 6 7檢索該值。
一般賦予浮點(diǎn)列的值被四舍五入到這個列所指定的十進(jìn)制數(shù)。如果在一個F L O AT(8, 1)的列中存儲1 . 2 3 4 5 6,則結(jié)果為1 . 2。如果將相同的值存入F L O AT(8, 4) 的列中,則結(jié)果為1 . 2 3 4 6。這表示應(yīng)該定義具有足夠位數(shù)的浮點(diǎn)列以便得到盡可能精確的值。如果想精確到千分之一,那就不要定義使該類型僅有兩位小數(shù)。
浮點(diǎn)值的這種處理在MySQL 3.23 中有例外,F(xiàn) L O AT(4) 和F L O AT(8) 的性能有所變化。這兩種類型現(xiàn)在為單精度( 4 字節(jié))和雙精度( 8 字節(jié))的類型,在其值按給出的形式存放(只受硬件的限制)這一點(diǎn)上說,這兩種類型是真浮點(diǎn)類型。
DECIMAL 類型不同于F L O AT 和D E C I M A L,其中DECIMAL 實(shí)際是以串存放的。DECIMAL 可能的最大取值范圍與DOUBLE 一樣,但是其有效的取值范圍由M 和D 的值決定。如果改變M 而固定D,則其取值范圍將隨M 的變大而變大。表2 - 7的前三行說明了這一點(diǎn)。如果固定M 而改變D,則其取值范圍將隨D 的變大而變?。ǖ仍黾樱1? - 7的后三行說明了這一點(diǎn)。
給定的DECIMAL 類型的取值范圍取決于MySQL 的版本。對于MySQL 3.23 以前的版本,DECIMAL(M, D) 列的每個值占用M 字節(jié),而符號(如果需要)和小數(shù)點(diǎn)包括在M 字節(jié)中。因此,類型為DECIMAL(5, 2) 的列,其取值范圍為-9.99 到9 9 . 9 9,因?yàn)樗鼈兏采w了所有可能的5 個字符的值。
正如MySQL 3.23 一樣,DECIMAL 值是根據(jù)ANSI 規(guī)范進(jìn)行處理的, ANSI 規(guī)范規(guī)定DECIMAL(M, D) 必須能夠表示M 位數(shù)字及D 位小數(shù)的任何值。例如, DECIMAL(5, 2) 必須能夠表示從-999.99 到999.99 的所有值。而且必須存儲符號和小數(shù)點(diǎn),因此自MySQL 3.23以來DECIMAL 值占M + 2 個字節(jié)。對于DECIMAL(5, 2),“最長”的值(- 9 9 9 . 9 9)需要7個字節(jié)。在正取值范圍的一端,不需要正號,因此MySQL 利用它擴(kuò)充了取值范圍,使其超
過了ANSI 所規(guī)范所要求的取值范圍。如DECIMAL(5, 2) 的最大值為9 9 9 9 . 9 9,因?yàn)橛? 個字節(jié)可用。
簡而言之,在MySQL 3.23 及以后的版本中,DECIMAL(M, D) 的取值范圍等于更早版本中的DECIMAL(M + 2, D) 的取值范圍。在MySQL 的所有版本中,如果某個DECIMAL 列的D 為0,則不存儲小數(shù)點(diǎn)。這樣做的結(jié)果是擴(kuò)充了列的取值范圍,因?yàn)檫^去用來存儲小數(shù)點(diǎn)的字節(jié)現(xiàn)在可用來存放其他數(shù)字了。
1. 數(shù)值列的類型屬性
可對所有數(shù)值類型指定ZEROFILL 屬性。它使相應(yīng)列的顯示值用前導(dǎo)零來填充,以達(dá)到顯示寬度。在希望確定列值總是以給定的數(shù)字位數(shù)顯示時可利用Z E R O F I L L。實(shí)際上,更準(zhǔn)確地說是“一個給定的最小數(shù)目的數(shù)字位數(shù)”,因?yàn)楸蕊@示寬度更寬的值可完全顯示而未被剪裁。使用下列語句可看到這一點(diǎn):
其中SELECT 語句的輸出結(jié)果如下。請注意最后一行值,它比列的顯示寬度更寬,但仍然完全顯示出來:
如下所示兩個屬性只用于整數(shù)列:
■ AUTO_INCREMENT。在需要產(chǎn)生唯一標(biāo)識符或順序值時,可利用AUTO_ INCREMENT屬性。A U TO_INCREMENT 值一般從1開始,每行增加1。在插入NULL 到一個A U TO _INCREMENT 列時,MySQL 插入一個比該列中當(dāng)前最大值大1 的值。一個表中最多只能有一個A U TO_INCREMENT 列。對于任何想要使用A U TO_INCREMENT 的列,應(yīng)該定義為NOT NULL,并定義為P R I M A RY KEY 或定義為UNIQUE 鍵。例如, 可按下列任何一種方式定義AUTO_INCREMENT 列:
A U TO_INCREMENT 的性能將在下一小節(jié)“使用序列”中作進(jìn)一步的介紹。
■ U N S I G N E D。此屬性禁用負(fù)值。將列定義為UNSIGNED 并不改變其基本數(shù)據(jù)類型的取值范圍;它只是前移了取值的范圍??紤]下列的表說明:
itiny 和itiny_u 兩列都是T I N Y I N T列,并且都可取2 5 6個值,但是i t i n y的取值范圍為-1 2 8 到1 2 7,而itiny_u 的取值范圍為0 到2 5 5。UNSIGNED 對不取負(fù)值的列是非常有用的,如存入人口統(tǒng)計(jì)或出席人數(shù)的列。如果用常規(guī)的有符號列來存儲這樣的值,那么就只利用了該列類型取值范圍的一半。通過使列為U N S I G N E D,能有效地成倍增加其取值范圍。如果將列用于序列號,且將它設(shè)為U N S I G N E D,則可取原雙倍的值。在指定以上屬性之后(它們是專門用于數(shù)值列的),可以指定通用屬性NULL 或N O TN U L L。如果未指定NULL 或NOT NULL,則缺省為N U L L。也可以用D E FA U LT 屬性來指定一個缺省值。如果不指定缺省值,則會自動選擇一個。對于所有數(shù)值列類型,那些可以包含NULL 的列的缺省將為N U L L,不能包含NULL 的列其缺省為0。下面的樣例創(chuàng)建三個INT 列,它們分別具有缺省值-1、1 和N U L L:
2. 使用序列
許多應(yīng)用程序出于標(biāo)識的目的需要使用唯一的號碼。需要唯一值的這種要求在許多場合都會出現(xiàn),如:會員號、試驗(yàn)樣品編號、顧客I D、錯誤報告或故障標(biāo)簽等等。A U TO_INCREMENT 列可提供唯一編號。這些列可自動生成順序編號。本節(jié)描述A U TO_INCREMENT 列是怎樣起作用的,從而使您能夠有效地利用它們而不至于出錯。另外,還介紹了怎樣不用A U TO_INCREMENT 列來產(chǎn)生序列的方法。
(1) MySQL 3.23 以前的版本中的A U TO _ I N C R E M E N TMySQL 3.23 版以前的A U TO_INCREMENT 列的性能如下:
■ 插入NULL 到A U TO_INCREMENT 列,使MySQL 自動地產(chǎn)生下一個序列號并將此序列號自動地插入列中。A U TO_INCREMENT 序列從1 開始,因此插入表中的第一個記錄得到為1 的序列值,而后繼插入的記錄分別得到序列值2、3 等等。一般,每個自動生成的值都比存儲在該列中的當(dāng)前最大值大1。
■ 插入0 到A U TO_INCREMENT 與插入NULL 到列中的效果一樣。插入一行而不指定A U TO_INCREMENT 列的值也與插入NULL 的效果一樣。
■ 如果插入一個記錄并明確指定A U TO_INCREMENT 列的一個值,將會發(fā)生兩件事之一。如果已經(jīng)存在具有該值的某個記錄,則出錯,因?yàn)锳 U TO_INCREMENT 列中的值必須是惟一的。如果不存在具有該值的記錄,那么新記錄將被插入,并且如果新記錄的A U TO_INCREMENT 列中的值是新的最大值,那么后續(xù)行將用該值的下一個值。換句話說,也就是可以通過插入一個具有比當(dāng)前值大的序列值的記錄,來增大序列的計(jì)數(shù)器。增大計(jì)數(shù)器會使序列出現(xiàn)空白,但這個特性也有用。例如創(chuàng)建一個具有A U TO _INCREMENT 列的表,但希望序列從1000 而不是1 開始。則可以用后述的兩種辦法之一達(dá)到此目的。一個辦法是插入具有明確序列值1000 的第一個記錄,然后通過插入NULL 到A U TO_INCREMENT 列來插入后續(xù)的記錄。另一個辦法是插入
A U TO_INCREMENT 列值為999 的假記錄。然后第一個實(shí)際插入的記錄將得到一個序列號1 0 0 0,這時再將假記錄刪除。
■ 如果將一個不合規(guī)定的值插入A U TO_INCREMENT 列,將會出現(xiàn)難以預(yù)料的結(jié)果。
■ 如果刪除了在A U TO_INCREMENT 列中含有最大值的記錄,則此值在下一次產(chǎn)生新值時會再次使用。如果刪除了表中的所有記錄,則所有值都可以重用;相應(yīng)的序列重新從1開始。
■ REPLACE 語句正常起作用。
■ U P D ATE 語句按類似插入新記錄的規(guī)則起作用。如果更新一個A U TO _ I N C R E M E N T列為NULL 或0,則會自動將其更新為下一個序列號。如果試圖更新該列為一個已經(jīng)存在的值,將出錯(除非碰巧設(shè)置此列的值為它所具有的值,才不會出錯,但這沒有任何意義)。如果更新該列的值為一個比當(dāng)前任何列值都大的值,則以后序列將從下一個值繼續(xù)進(jìn)行編號。
■ 最近自動產(chǎn)生的序列編號值可調(diào)用L A S T _ I N S E RT_ID( ) 函數(shù)得到。它使得能在其他不知道此值的語句中引用A U TO_INCREMENT 值。L A S T _ I N S E RT_ID( ) 依賴于當(dāng)前服務(wù)器會話中生成的A U TO_INCREMENT 值; 它不受與其他客戶機(jī)相關(guān)的A U TO_INCREMENT 活動的影響。如果當(dāng)前會話中沒有生成A U TO_INCREMENT 值,則L A S T _ I N S E RT_ID( ) 返回0。能夠自動生成順序編號這個功能特別有用。但是剛才介紹的A U TO_INCREMENT 性能有兩個缺陷。首先,序列中頂上的記錄被刪除時,序列值的重用使得難于生成可能刪除和插入記錄的應(yīng)用的一系列單調(diào)(嚴(yán)格遞增)值。其次,利用從大于1的值開始生成序列的方法是很笨的。
(2) MySQL 3.23 版以后的A U TO_INCREMENTMySQL 3.23 對A U TO_INCREMENT 的性能進(jìn)行了下列變動以便能夠處理上述問題:
■ 自動順序生成的值嚴(yán)格遞增且不重用。如果最大的值為143 并刪除了包含這個值的記錄,MySQL 繼續(xù)生成下一個值1 4 4。
■ 在創(chuàng)建表時,可以明確指定初始的序列編號。下面的例子創(chuàng)建一個A U TO _ I N C R E -MENT 列seq 從1,000,000 開始的表:
在一個表具有多個列時(正如多數(shù)表那樣),最后的A U TO_INCREMENT = 1000000子句應(yīng)用到哪一列是不會混淆的,因?yàn)槊總€表只能有一個A U TO_INCREMENT 列。
(3) 使用A U TO_INCREMENT 應(yīng)該考慮的問題在使用A U TO_INCREMENT 列時,應(yīng)該記住下列要點(diǎn):
■ A U TO_INCREMENT 不是一種列類型,它只是一種列類型屬性。此外, A U TO _INCREMENT 是一種只能用于整數(shù)類型的屬性。MySQL 早于3.23 的版本并不嚴(yán)格服從這個約束,允許定義諸如CHAR 這樣的列類型具有A U TO_INCREMENT 屬性。但是只有整數(shù)類型作為A U TO_INCREMENT 列正常起作用。
■ A U TO_INCREMENT 機(jī)制的主要目的是生成一個正整數(shù)序列,并且如果以這種方式使用,則A U TO_INCREMENT 列效果最好。所以應(yīng)該定義A U TO_INCREMENT 列為U N S I G N E D。這樣做的優(yōu)點(diǎn)是在到達(dá)列類型的取值范圍上限前可以進(jìn)行兩倍的序列編號。在某些環(huán)境下,也有可能利用A U TO_INCREMENT 列來生成負(fù)值的序列,但是我們不建議這樣做。如果您決定要試一下,應(yīng)該保證進(jìn)行充分的試驗(yàn),并且在升級到不同的MySQL 版本時需要重新測試。筆者的經(jīng)驗(yàn)表明,不同的版本中,負(fù)序列的性能并不完全一致。
■ 不要認(rèn)為對某個列定義增加A U TO_INCREMENT 是一個得到無限的編號序列的奇妙方法。事實(shí)并非這樣; A U TO_INCREMENT 序列受基礎(chǔ)列類型的取值范圍所限制。例如,如果使用TINYINT UNSIGNED 列,則最大的序列號為2 5 5。在達(dá)到這個界限時,應(yīng)用程序?qū)㈤_始出現(xiàn)“重復(fù)鍵”錯誤。
■ MySQL 3.23 引入了不重用序列編號的新A U TO_INCREMENT 性能,并且允許在C R E ATE TABLE 語句中指定一個初始的序列編號。這些性能在使用下列形式的DELETE 語句刪除了表中所有記錄后可以撤消:
在此情形下,序列重新從1開始而不按嚴(yán)格的增量順序繼續(xù)增加。即使在C R E AT ETABLE 語句中明確指定了一個初始的序列編號,相應(yīng)的序列也會從頭開始。出現(xiàn)這種情形的原因在于MySQL 優(yōu)化完全刪空一個表的DELETE 語句的方法上;它從頭開始重新創(chuàng)建數(shù)據(jù)文件和索引文件而不是去刪除每個記錄,這樣就丟失了所有的序列號信息。如果要刪除所有記錄,但希望保留序列信息,可以取消優(yōu)化并強(qiáng)制MySQL 執(zhí)行逐行的刪除操作,如下所示:
如果使用的是3 . 2 3以上的版本,怎樣保持嚴(yán)格的增量序列?方法之一是保持一個只用來生成A U TO_INCREMENT 值的獨(dú)立的表,永遠(yuǎn)不從這個表中刪除記錄。在這種情況下,獨(dú)立表中的值永遠(yuǎn)不會重用。在主表中需要生成一個新記錄時,首先在序列編號表中插入一個N U L L。然后對希望包含序列編號的列使用L A S T _ I N S E RT_ID( ) 的值將該記錄插入主表,如下所示:
如果想要編寫一個生成A U TO_INCREMENT 值的應(yīng)用程序,但希望序列從100 而不是1開始。再假定希望這個程序可移植到所有MySQL 版本。怎樣來完成它呢?如果可移植是一個目標(biāo),那么不能依賴MySQL 3.23 所提供的在C R E ATE TABLE 語句中指定初始序列編號的功能。而是在想要插入一個記錄時,首先用下列語句檢查表是否是空的:
這個步驟雖然是附加的,但不會花費(fèi)太多的時間,因?yàn)闆]有WHERE 子句的SELECT COUNT(*) 是優(yōu)化的,返回很快。如果表是空的,則插入記錄并明確地對序列編號列指定值1 0 0。如果表不空,則對序列編號列值指定NULL 使MySQL 自動生成下一個編號。此方法允許插入序列編號為1 0 0、101 等的記錄,它不管MySQL 是否允許指定初始序列值都能正常工作。如果要求序列編號即使是從表中刪除了記錄后也要嚴(yán)格遞增,則此方法不起作用。在這樣的情形下,可將此方法與前面描述的什么也不做只是用來產(chǎn)生用于主表的序列編號的輔助表技術(shù)結(jié)合使用。為什么會希望從一個大于1 的序列編號開始呢?一個原因是想使所有序列編號全都具有相同的數(shù)字位數(shù)。如果需要生成顧客ID 號,并且希望不要多于一百萬個顧客,則可以從1 000 000
開始編號。在對顧客ID 值計(jì)數(shù)的數(shù)字位數(shù)改變之前,可以追加一百萬個顧客。當(dāng)然,強(qiáng)制序列編號為一個固定寬度的另一個方法是采用ZEROFILL 列。對于有的情形,這樣做有可能會出問題。例如,如果在Perl 或PHP 腳本中處理具有前導(dǎo)零的序列編號,則必須仔細(xì)地將它們只作為串使用;如果將它們轉(zhuǎn)換成數(shù)字,前導(dǎo)零將會丟失。下面的短Perl 腳本說明了處理編號時可能會出的問題:
打印時,此腳本給出下列輸出:
P e r l’s‘+ +’自動增量操作是很靈巧的而且可以利用串或數(shù)值建立序列值,但‘+ =’操作只應(yīng)用于數(shù)值。在所顯示的輸出中,可看到‘ + =’引起串到數(shù)值的轉(zhuǎn)換并且丟失了$s 值中的前導(dǎo)零。
序列不從1開始的另一個原因從技術(shù)的角度來說可能不值一提。例如,在分配會員號時,序列號不要從1開始,以免出現(xiàn)關(guān)于誰是第一號的政治爭論。
(4) 不用A U TO_INCREMENT 生成序列生成序列號的另一個方法根本就不需要使用A U TO_INCREMENT 列。它利用取一個參數(shù)的L A S T _ I N S E RT_ID( ) 函數(shù)的變量來生成序列號。(這種形式在MySQL 3.22.9. 中引入)如果利用L A S T _ I N S E RT_ID(expr) 來插入或更新一個列, 則下一次不用參數(shù)調(diào)用L A S T _ I N S E RT_ID( ) 時,將返回expr 的值。換句話說,就像由A U TO_INCREMENT 機(jī)制生成的那樣對expr 進(jìn)行處理。這樣使得能生成一個序列號,然后可在以后的客戶會話中利用它,用不著取受其他客戶機(jī)影響的值。利用這種策略的一種方法是創(chuàng)建一個包含一個值的單行表,該值在想得到序列中下一個值時進(jìn)行更新。例如,可創(chuàng)建如下的表:
上面的語句創(chuàng)建了表seq_table 并用包含seq 值0 的行對其進(jìn)行初始化??衫眠@個表產(chǎn)生下一個序列號,如下所示:
該語句取出seq 列的當(dāng)前值并對其加1,產(chǎn)生序列中的下一個值。利用L A S T _ I N S E RT _ID(seq + 1) 生成新值使它就像一個AUTO_INCREMENT 值一樣,而且此值可在以后的語句中通過調(diào)用無參數(shù)的L A S T _ I N S E RT_ID( ) 來取出。即使某個其他客戶機(jī)同時生成了另一個序列號,上述作用也不會改變,因?yàn)長 A S T _ I N S E RT_ID( ) 是客戶機(jī)專用的。如果希望生成增量不是1 的編號序列或負(fù)增量的編號序列,也可以利用這個方法。例如,下面兩個語句可以用來分別生成一個增量為100 的編號序列和一個負(fù)的編號序列:
通過將seq 列設(shè)置為相應(yīng)的初始值,可利用這個方法生成以任意值開始的序列。關(guān)于將此序列生成方法用于多個計(jì)數(shù)器的應(yīng)用,可參閱第3章。
2.2.3 串列類型
MySQL 提供了幾種存放字符數(shù)據(jù)的串類型。串常常用于如下這樣的值:
在某種意義上,串實(shí)際是一種“通用”類型,因?yàn)榭捎盟鼈儊肀硎救我庵怠@?,可用串類型來存儲二進(jìn)制數(shù)據(jù),如影像或聲音,或者存儲gzip 的輸出結(jié)果,即存儲壓縮數(shù)據(jù)。對于所有串類型,都要剪裁過長的值使其適合于相應(yīng)的串類型。但是串類型的取值范圍很不同,有的取值范圍很小,有的則很大。取值大的串類型能夠存儲近4GB 的數(shù)據(jù)。因此,應(yīng)該使串足夠長以免您的信息被切斷(由于受客戶機(jī)/服務(wù)器通信協(xié)議的最大塊尺寸限制,列
值的最大限額為2 4 M B)。
表2 - 8給出了MySQL 定義串值列的類型,以及每種類型的最大尺寸和存儲需求。對于可變長的列類型,各行的值所占的存儲量是不同的,這取決于實(shí)際存放在列中的值的長度。這個長度在表中用L 表示。
L 以外所需的額外字節(jié)為存放該值的長度所需的字節(jié)數(shù)。MySQL 通過存儲值的內(nèi)容及其長度來處理可變長度的值。這些額外的字節(jié)是無符號整數(shù)。請注意,可變長類型的最大長度、此類型所需的額外字節(jié)數(shù)以及占用相同字節(jié)數(shù)的無符號整數(shù)之間的對應(yīng)關(guān)系。例如,
MEDIUMBLOB 值可能最多22 4 - 1字節(jié)長并需要3 個字節(jié)記錄其結(jié)果。3 個字節(jié)的整數(shù)類型MEDIUMINT 的最大無符號值為22 4 - 1。這并非偶然。
1. CHAR 和VARCHAR 列類型
CHAR 和VARCHAR 是最常使用的串類型。它們是有差異的, CHAR 是定長類型而VARCHAR 是可變長類型。CHAR(M) 列中的每個值占M 個字節(jié);短于M 個字節(jié)的值存儲時在右邊加空格(但右邊的空格在檢索時去掉)。VARCHAR(M) 列的值只用所必需的字節(jié)數(shù)來存放(結(jié)尾的空格在存儲時去掉,這與ANSI SQL 的VARCHAR 值的標(biāo)準(zhǔn)不同),然后再加一個字節(jié)記錄其長度。如果所需的值在長度上變化不大,則CHAR 是一種比VARCHAR 好的選擇,因?yàn)樘幚硇虚L度固定的表比處理行長度可變的表的效率更高。如果所有的值長度相同,由于需要額外的字節(jié)來記錄值的長度,VARCHAR 實(shí)際占用了更多的空間。在MySQL 3.23 以前,CHAR 和VARCHAR 列用最大長度為1 到255 的M 來定義。從MySQL 3.23 開始,CHAR(0) 也是合法的了。在希望定義一個列,但由于尚不知道其長度,所以不想給其分配空間的情況下, CHAR(0) 列作為占位符很有用處。以后可以用A LT E RTABLE 來加寬這個列。如果允許其為N U L L,則CHAR(0) 列也可以用來表示o n / o ff 值。這樣的列可能取兩個值,NULL 和空串。CHAR(0) 列在表中所占的空間很小,只占一位。除少數(shù)情況外,在同一個表中不能混用CHAR 和VA R C H A R。MySQL 根據(jù)情況甚至?xí)⒘袕囊环N類型轉(zhuǎn)換為另一種類型。這樣做的原因如下:
■ 行定長的表比行可變長的表容易處理(其理由請參閱2 . 3節(jié)“選擇列的類型”)。
■ 表行只在表中所有行為定長類型時是定長的。即使表中只有一列是可變長的,該表的行也是可變長的。
■ 因?yàn)樵谛锌勺冮L時定長行的性能優(yōu)點(diǎn)完全失去。所以為了節(jié)省存儲空間,在這種情況下最好也將定長列轉(zhuǎn)換為可變長列。這表示,如果表中有VARCHAR 列,那么表中不可能同時有CHAR 列;MySQL 會自動地將它們轉(zhuǎn)換為VARCHAR 列。例如創(chuàng)建如下一個表:
請注意,VARCHAR 列的出現(xiàn)使MySQL 將c1 也轉(zhuǎn)換成了VARCHAR 類型。如果試圖用A LTER TABLE 將c1 轉(zhuǎn)換為C H A R,將不起作用。將VARCHAR 列轉(zhuǎn)換為CHAR 的惟一辦法是同時轉(zhuǎn)換表中所有VARCHAR 列:
BLOB 和TEXT 列類型像VARCHAR 一樣是可變長的,但是它們沒有定長的等價類型,因此不能在同一表中與BLOB 或TEXT 列一起使用CHAR 列。這時任何CHAR 列都將被轉(zhuǎn)換為VARCHAR 列。定長與可變長列混用的情形是在CHAR 列短于4 個字符時,可以不對其進(jìn)行轉(zhuǎn)換。例如,MySQL 不會將下面所創(chuàng)建的表中的CHAR 列轉(zhuǎn)換為VARCHAR 列:
短于4個字符的列不轉(zhuǎn)換的原因是,平均情況下,不存儲尾空格所節(jié)省的空間被VA R C H A R列中記錄每個值的長度所需的額外字節(jié)所抵消了。實(shí)際上,如果所有列都短, MySQL 將會把所定義的所有列從VARCHAR 轉(zhuǎn)換為C H A R。MySQL 這樣做的原因是,這種轉(zhuǎn)換平均來說不會增加存儲需求,而且使表行定長,從而改善了性能。如果按如下創(chuàng)建一個表,VARCHAR 列全都會轉(zhuǎn)換為CHAR 列:
2. BLOB 與TEXT 列類型
BLOB 是一個二進(jìn)制大對象,是一個可以存儲大量數(shù)據(jù)的容器,可以使其任意大。在MySQL 中,BLOB 類型實(shí)際是一個類型系列( T I N Y B L O B、B L O B、M E D I U M B L O B、L O N G B L O B),除了在可以存儲的最大信息量上不同外(請參閱表2 - 8),它們是等同的。
MySQL 還有一個TEXT 類型系列( T I N Y T E X T、T E X T、M E D I U M T E X T、L O N G T E X T)。除了用于比較和排序外,它們在各個方面都與相應(yīng)的BLOB 類型等同,BLOB 值是區(qū)分大小寫的,而TEXT 值不區(qū)分大小寫。BLOB 和TEXT 列對于存儲可能有很大增長的值或各行大小有很大變化的值很有用,例如,字處理文檔、圖像和聲音、混合數(shù)據(jù)以及新聞文章等等。BLOB 或TEXT 列在MySQL 3.23 以上版本中可以進(jìn)行索引,雖然在索引時必須指定一個用于索引的約束尺寸,以免建立出很大的索引項(xiàng)從而抵消索引所帶來的好處。除此之外,一般不通過查找BLOB 或TEXT 列來進(jìn)行搜索,因?yàn)檫@樣的列常常包含二進(jìn)制數(shù)據(jù)(如圖像)。常見的做法是用表中另外的列來記錄有關(guān)BLOB 或TEXT 值的某種標(biāo)識信息,并用這些信息來確定想要哪些行。使用BLOB 和TEXT 列需要特別注意以下幾點(diǎn):
■ 由于BLOB 和TEXT 值的大小變化很大,如果進(jìn)行的刪除和更新很多,則存儲它們的
表出現(xiàn)高碎片率會很高。應(yīng)該定期地運(yùn)行OPTIMIZE TABLE 減少碎片率以保持良好的
性能。要了解更詳細(xì)的信息請參閱第4章。
■ 如果使用非常大的值,可能會需要調(diào)整服務(wù)器增加max_allowed_packet 參數(shù)的值。詳細(xì)的信息請參閱第11章“常規(guī)的MySQL 管理”。如果需要增加希望使用非常大的值的客戶機(jī)的塊尺寸,可見附錄E“MySQL 程序參考”,該附錄介紹了怎樣對mysql 和mysqldump 客戶機(jī)進(jìn)行這種塊尺寸的增加。
3. ENUM 和SET 列類型
ENUM 和SET 是一種特殊的串類型,其列值必須從一個固定的串集中選擇。它們之間的主要差別是ENUM 列值必須確實(shí)是值集中的一個成員,而SET 列值可以包括集合中任意或所有的成員。換句話說, ENUM 用于互相排斥的值,而S E T列可以從一個值的列表中選擇多個值。
ENUM 列類型定義了一個枚舉??少x予ENUM 列一個在創(chuàng)建表時指定的值列表中選擇的成員。枚舉可具有最多65 536 個成員(其中之一為MySQL 保留)。枚舉通常用來表示類別值。例如,定義為E N U M (“N”, “Y”) 的列中的值可以是“N”或“Y”?;蛘呖蓪NUM 用于諸如調(diào)查或問卷中的多項(xiàng)選擇問題,或用于某個產(chǎn)品的可能尺寸或顏色等:
如果正在處理Web 頁中的選擇,那么可以利用ENUM 來表示站點(diǎn)訪問者在某頁上的互相排斥的單選鈕集合中進(jìn)行的選擇。例如,如果運(yùn)行一個在線比薩餅訂購服務(wù)系統(tǒng),可用ENUM 來表示顧客訂購的比薩餅形狀:
如果枚舉類別表示計(jì)數(shù),在建立該枚舉時最重要的是選擇合適的類別。例如,在記錄實(shí)驗(yàn)室檢驗(yàn)中白血球的數(shù)目時,可能會將計(jì)數(shù)分為如下的幾組:
在某個測試結(jié)果以精確的計(jì)數(shù)到達(dá)時,要根據(jù)該值所屬的類別來記錄它。但如果想將列從基于類別的ENUM 轉(zhuǎn)換為基于精確計(jì)數(shù)的整數(shù)時,不可能恢復(fù)原來的計(jì)數(shù)。在創(chuàng)建SET 列時,要指定一個合法的集合成員列表。在這種意義上, SET 類型與E N U M是類似的。但是SET 與ENUM 不同,每個列值可由來自集合中任意數(shù)目的成員組成。集合中最多可有64 個成員。對于值之間互斥的固定集合,可使用SET 列類型。例如,可利用SET 來表示汽車的可用選件,如下所示:
然后,特定的SET 值將表示顧客實(shí)際訂購哪些選件,如下所示:
空串表示顧客未訂購任何選件。這是一個合法的SET 值。SET 列值為單個串。如果某個值由多個集合成員組成,那么這些成員在串中用逗號分隔。顯然,這表示不應(yīng)該用含有逗號的串作為SET 成員。SET 列的其他用途是表示諸如病人的診斷或來自Web 頁的選擇結(jié)果這樣的信息。對于診斷,可能會有一個向病人提問的標(biāo)準(zhǔn)癥狀清單,而病人可能會表現(xiàn)出某些癥狀或所有的癥狀。對于在線比薩餅服務(wù)系統(tǒng),用于訂購的Web 頁應(yīng)該具有一組復(fù)選框,用來表示顧客想在比薩餅上加的配料。對ENUM 或SET 列的合法值列表的定義很重要,例如:
■ 正如上面所介紹的,此列表決定了列的可能合法值。
■ 可按任意的大小寫字符插入ENUM 或SET 值,但是列定義中指定的串的大小寫字符決定了以后檢索它們時的大小寫。例如,如果有一個E N U M (“Y”, “N”) 列,但您在其中存儲了“ y”和“n”,當(dāng)您檢索出它們時顯示的是“ Y”和“N”。這并不影響比較或排序的狀態(tài),因?yàn)镋NUM 和SET 列是不區(qū)分大小寫的。
■ 在ENUM 定義中的值順序就是排序順序。SET 定義中的值順序也決定了排序順序,但是這個關(guān)系更為復(fù)雜,因?yàn)榱兄悼赡馨ǘ鄠€集合成員。
■ SET 定義中的值順序決定了在顯示由多個集合成員組成的SET 列值時,子串出現(xiàn)的順序。
ENUM 和SET 被歸為串類型是由于在建立這些類型的列時,枚舉和集合成員被指定為串。但是,這些成員在內(nèi)部存放時作為數(shù)值,而且同樣可作為數(shù)值來處理。這表示ENUM 和S E T類型比其他的串類型更為有效,因?yàn)橥ǔ?捎脭?shù)值運(yùn)算而不是串運(yùn)算來處理它們。而且這還表示ENUM 和SET 值可用在串或數(shù)值的環(huán)境中。
列定義中的ENUM 成員是從1 開始順序編號的。(0 被MySQL 用作錯誤成員,如果以串的形式表示就是空串。)枚舉值的數(shù)目決定了ENUM 列的存儲大小。一個字節(jié)可表示256 個值,兩個字節(jié)可表示65 536 個值。(可將其與一字節(jié)和兩字節(jié)的整數(shù)類型T I N Y I N T、
UNSIGNED 和SMALLINT UNSIGNED 進(jìn)行對比。)因此,枚舉成員的最大數(shù)目為65 536(包括錯誤成員),并且存儲大小依賴于成員數(shù)目是否多于256 個。在ENUM 定義中,可以最多指定65 535(而不是65 536)個成員,因?yàn)镸ySQL 保留了一個錯誤成員,它是每個枚舉的隱含成員。在將一個非法值賦給ENUM 列時,MySQL 自動將其換成錯誤成員。下面有一個例子,可用mysql 客戶機(jī)程序測試一下。它給出枚舉成員的數(shù)值順序,而且還說明了NULL 值無順序編號:
可對ENUM 成員按名或者按編號進(jìn)行運(yùn)算,例如:
可以定義空串為一個合法的枚舉成員。與列在定義中的其他成員一樣,它將被賦予一個非零的數(shù)值。但是使用空串可能會引起某些混淆,因?yàn)樵摯脖蛔鳛閿?shù)值為0 的錯誤成員。在下面的例子中,將非法的枚舉值“ x”賦予ENUM 列引起了錯誤成員的賦值。僅在以數(shù)值
形式進(jìn)行檢索時,才能夠與空串區(qū)分開:
SET 列的數(shù)值表示與ENUM 列的表示有所不同,集合成員不是順序編號的。每個成員對應(yīng)SET 值中的一個二進(jìn)制位。第一個集合成員對應(yīng)于0 位,第二個成員對應(yīng)于1 位,如此等等。數(shù)值SET 值0 對應(yīng)于空串。SET 成員以位值保存。每個字節(jié)的8 個集合值可按此方式存
放,因此SET 列的存儲大小是由集合成員的數(shù)目決定的,最多64 個成員。對于大小為1 到8、9 到1 6、17 到2 4、25 到3 2、33 到64 個成員的集合,其SET 值分別占用1、2、3、4 或8個字節(jié)。
用一組二進(jìn)制位來表示SET 正是允許SET 值由多個集合成員組成的原因。值中二進(jìn)制位的任意組合都可以得到,因此,相應(yīng)的值可由對應(yīng)于這些二進(jìn)制位的SET 定義中的串組合構(gòu)成。下面給出一個說明SET 列的串形式與數(shù)值形式之間關(guān)系的樣例;數(shù)值以十進(jìn)制形式和二
進(jìn)制形式分別給出:
如果給SET 列賦予一個含有未作為集合成員列出的子串的值,那么這些子串被刪除,并將包含其余子串的值賦予該列。在賦值給SET 列時,子串不需要按定義該列時的順序給出。但是,在以后檢索該值時,各成員將按定義時的順序列出。假如用下面的定義定義一個S E T列來表示家具:
如果給這個列賦予“ c h a i r, couch, table”值,那么,“c o u c h”被放棄,因?yàn)樗皇羌系某蓡T。其次,以后檢索這個值時,顯示為“ table, chair”。之所以這樣是因?yàn)镸ySQL 針對所賦的值的每個子串決定各個二進(jìn)制位并在存儲值時將它們置為1?!癱 o u c h”不對應(yīng)二進(jìn)制位,則忽略。在檢索時,MySQL 按順序掃描各二進(jìn)制位,通過數(shù)值值構(gòu)造出串值,它自動地將子串排成定義列時給出的順序。這個舉動還表示,如果在一個值中不止一次地指定某個成員,但在檢索時它也只會出現(xiàn)一次。如果將“ lamp, lamp,lamp”賦予某個SET 列,檢索時也只會得出“l(fā) a m p”。MySQL 重新對SET 值中的成員進(jìn)行排序這個事實(shí)表示,如果用一個串來搜索值,則必須以正確的順序列出各成員。如果插入“ c h a i r, table”,然后搜索“c h a i r, table”,那么將找不到相應(yīng)的記錄;必須查找“ table, chair”才能找到。ENUM 和SET 列的排序和索引是根據(jù)列值的內(nèi)部值(數(shù)值值)進(jìn)行的。下面的例子可能會顯示不正確,因?yàn)楦鱾€值并不是按字母順序存儲的:
NULL 值排在其他值前(如果是降序,將排在其他值之后)。如果有一個固定的值集,并且希望按特殊的次序進(jìn)行排序,可利用ENUM 的排序順序。在創(chuàng)建表時做一個ENUM 列,并在該列的定義中以所想要的次序給出各枚舉值即可。如果希望ENUM 按正常的字典順序排序,可使用C O N C AT( ) 和排序結(jié)果將列轉(zhuǎn)換成一個非ENUM 串,如下所示:
4. 串列類型屬性
可對CHAR 和VARCHAR 類型指定B I N A RY 屬性使列值作為二進(jìn)制串處理(即,在比較和排序操作區(qū)分大小寫)。
可對任何串類型指定通用屬性NULL 和NOT NULL。如果兩者都不指定,缺省值為N U L L。但是定義某個串列為NOT NULL 并不阻止其取空串??罩挡煌谶z漏的值,因此,不要錯誤地認(rèn)為可以通過定義NOT NULL 來強(qiáng)制某個串列只包含非空的值。如果要求串值非
空,那么這是一個在應(yīng)用程序中必須強(qiáng)制實(shí)施的約束條件。
還可以對除BLOB 和TEXT 類型外的所有串列類型用D E FA U LT 屬性指定一個缺省值。如果不指定缺省值, MySQL 會自動選擇一個。對于可以包含NULL 的列,其缺省值為N U L L。對于不能包含NULL 的列,除ENUM 列外都為空串,在ENUM 列中,缺省值為第一個枚舉成員(對于SET 類型,在相應(yīng)的列不能包含NULL 時其缺省值實(shí)際上是空集,不過這里空集等價于空串)。
2.2.4 日期和時間列類型
MySQL 提供了幾種時間值的列類型,它們分別是: DATE、DATE TIME、TIME、TIMES TAMP 和YEAR。表2-9 給出了MySQL 為定義存儲日期和時間值所提供的這些類型,并給出了每種類型的合法取值范圍。YEAR 類型是在MySQL 3.22版本中引入的。其他類型在所有MySQL 版本中都可用。每種時間類型的存儲需求見表2 - 1 0。每個日期和時間類型都有一個“零”值,在插入該類型的一個非法值時替換成此值,見表2 - 11。這個值也是定義為NOT NULL 的日期和時間列的缺省值。
MySQL 表示日期時根據(jù)ANSI 規(guī)范首先給出年份。例如,1999 年12 月3 日表示為“1 9 9 9 - 1 2 - 0 3”。MySQL 允許在輸入日期
時有某些活動的余地。如能將兩個數(shù)字的年份轉(zhuǎn)換成四位數(shù)字的年份,而且在輸入小于10 的月份和日期時不用輸入前面的那位數(shù)字。但是必須首先給出年份。平常經(jīng)常使用的那些格式,如“ 1 2 / 3 / 9 9”或“3 / 1 2 / 9 9”,都是不正確的。MySQL 使用的日期表示規(guī)則請參閱“處理日期和時間列”小節(jié)。時間值按本地時區(qū)返回給服務(wù)器; MySQL 對返回給客戶機(jī)的值不作任何時區(qū)調(diào)整。
1. DATE、TIME 和DATETIME 列類型DATE、TIME 和DATETIME 類型存儲日期、時間以及日期和時間值的組合。其格式為“YYYY - MM - DD”、“h h : m m : s s”和“YYYY - MM - DD hh:mm:ss”。對于D ATETIME 類型,日期和時間部分都需要;如果將D ATE 值賦給DATETIME 列,MySQL 會自動地追加一個為“0 0 : 0 0 : 0 0”的時間部分。MySQL 對D ATETIME 和TIME 表示的時間在處理上稍有不同。對于D ATETIME ,時間部分表示某天的時間。而TIME 值表示占用的時間(這也就是為什么其取值范圍如此之大而且允許取負(fù)值的原因)。用TIME 值的最右邊部分表示秒,因此,如果插入一個“短”(不完全)的時間值,如“1 2 : 3 0”到TIME 列,則存儲的值為“ 0 0 : 1 2 : 3 0”,即被認(rèn)為是“12 分30 秒”。如果愿意,也可用TIME 列來表示天的時間,但是要記住這個轉(zhuǎn)換規(guī)則以免出問題。為了插入一個“12 小時30 分鐘”的值,必須將其表示為“ 1 2 : 3 0 : 0 0”。
2. TIMESTAMP 列類型
TIMES TAMP 列以YYYYMMDDhhmmss 的格式表示值,其取值范圍從19700101000000到2037 年的某個時間。此取值范圍與UNIX 的時間相聯(lián)系,在UNIX 的時間中,1970 年的第一天為“零天”,也就是所謂的“新紀(jì)元”。因此1970 年的開始決定了T I M E S TAMP 取值范圍的低端。其取值范圍的上端對應(yīng)于UNIX 時間上的四字節(jié)界限,它可以表示到2037年的值。(TIMES TAMP 值的上限將會隨著操作系統(tǒng)為擴(kuò)充UNIX 的時間值所進(jìn)行的修改而增加。這是在系統(tǒng)庫一級必須提及的。MySQL 也將利用這些更改。)TIMES TAMP 類型之所以得到這樣的名稱是因?yàn)樗趧?chuàng)建或修改某個記錄時,有特殊的記錄作用。如果在一個TIMES TAMP 列中插入NULL,則該列值將自動設(shè)置為當(dāng)前的日期和時間。在建立或更新一行但不明確給TIMES TAMP 列賦值時也會自動設(shè)置該列的值為當(dāng)前的日期和時間。但是,僅行中的第一個TIMES TAMP 列按此方式處理,即使是行中第一個TIMESTAMP列,也可以通過插入一個明確的日期和時間值到該列(而不是NULL)使該處理失效。
TIMES TAMP 列的定義可包含對最大顯示寬度M 的說明。表2 - 1 2給出了所允許的M 值的顯示格式。如果TIMES TAMP 定義中省略了M 或者其值為0或大于1 4,則該列按TIMES TAMP(14) 處理。取值范圍從1到1 3的M 奇數(shù)值作為下一個更大的偶數(shù)值處理。T I M E S TAMP 列的顯示寬度與存儲大小或存儲在內(nèi)部的值無關(guān)。TIMES TAMP 值總是以4 字節(jié)存放并按14 位精度進(jìn)行計(jì)算,與顯示寬度無關(guān)。為了明白這一點(diǎn),按如下定義一個表,然后插入一些行,進(jìn)行檢索:
從表面上看,出現(xiàn)的行排序有誤,第一列中的值全都相同,所以似乎排序是根據(jù)第二列中的值進(jìn)行的。這個表面反常的結(jié)果是由于事實(shí)上, MySQL 是根據(jù)插入T I M E S TAMP 列的全部14 位值進(jìn)行排序的。MySQL 沒有可在記錄建立時設(shè)置為當(dāng)前日期和時間、并從此以后保持不變的列類型。如果要實(shí)現(xiàn)這一點(diǎn),可用兩種方法來完成:
■ 使用T I M E S TAMP 列。在最初建立一個記錄時,設(shè)置該列為N U L L,將其初始化為當(dāng)前日期和時間:
在以后無論何時更改此記錄,都要明確地設(shè)置此列為其原有的值。賦予一個明確的值使時間戳機(jī)制失效,因?yàn)樗柚沽嗽摿械闹底詣痈拢?div style="height:15px;">
■ 使用D ATETIME 列。在建立記錄時,將該列的值初始化為NOW( ):
無論以后何時更新此記錄,都不能動該列:U P D ATE tbl_name SET /* angthing BUT dt_col here */ WHERE ...如果想利用T I M E S TAMP 列既保存建立的時間值又保存最后修改的時間值,那么可用一個T I M E S TAMP 列來保存修改時間值,用另一個T I M E S TAMP 列保存建立時間值。要保證保存修改時間值的列為第一個T I M E S TA M P,從而在記錄建立或更改時自動對其進(jìn)行設(shè)置。使保存建立時間值的列為第二個T I M E S TA M P,并在建立新記錄時將其初始化為NOW( )。這樣第二個T I M E S TAMP 的值將反映記錄建立時間,而且以后將不再更改。
3. YEAR 列類型
YEAR 是一個用來有效地表示年份值的1個字節(jié)的列類型。其取值范圍為從1901 到2 1 5 5。在想保存日期信息但又只需要日期的年份時可使用YEAR 類型,如出生年份、政府機(jī)關(guān)選舉年份等等。在不需要完全的日期值時, YEAR 比其他日期類型在空間利用上更為有效。
YEAR 列的定義可包括顯示寬度M 的說明,顯示寬度應(yīng)該為4 或2。如果YEAR 定義中省略了M,其缺省值為4。TINYINT 與YEAR 具有相同的存儲大小(一個字節(jié)),但取值范圍不同。要使用一個整數(shù)類型且覆蓋與YEAR 相同的取值范圍,可能需要SMALLINT 類型,此類型要占兩倍的空間。在所要表示的年份取值范圍與YEAR 類型的取值范圍相同的情況下, YEAR 的空間利用率比SMALLINT 更為有效。YEAR 相對整數(shù)列的另一個優(yōu)點(diǎn)是MySQL 將會利用MySQL 的年份推測規(guī)則把2 位值轉(zhuǎn)換為4 位值。例如,97 與14 將轉(zhuǎn)換為1997 和2 0 1 4。但要認(rèn)識到,插入數(shù)值00 將得到0000 而不是2 0 0 0。如果希望零值轉(zhuǎn)換為2 0 0 0,必須指定其為串“0 0”。
4. 日期和時間列類型的屬性沒有專門針對日期和時間列類型的屬性。通用屬性NULL 和NOT NULL 可用于任意日期和時間類型。如果NULL 和NOT NULL 兩者都不指定,則缺省值為N U L L。也可以用DEFA ULT 屬性指定一個缺省值。如果不指定缺省值,將自動選擇一個缺
省值。含有NULL 的列的缺省值為NULL 。否則,缺省值為該類型的“零”值。
5. 處理日期和時間列MySQL 可以理解各種格式的日期和時間值。D ATE 值可按后面的任何一種格式指定,其中包括串和數(shù)值形式。表2 - 1 3為每種日期和時間類型所允許的格式。兩位數(shù)字的年度值的格式用“歧義年份值的解釋”中所描述的規(guī)則來解釋。對于有分隔
符的串格式,不一定非要用日期的“ -”符號和時間的“ :”符號來分隔,任何標(biāo)點(diǎn)符號都可用作分隔符,因?yàn)橹档慕忉屓Q于上下文,而不是取決于分隔符。例如,雖然時間一般是用分隔符“:”指定的,但MySQL 并不會在一個需要日期的上下文中將含有“ :”號的值理解成時間。此外,對于有分隔符的串格式,不需要為小于10 的月、日、小時、分鐘或秒值指定兩個數(shù)值。下列值是完全等同的:
請注意,有前導(dǎo)零的值根據(jù)它們被指定為串或數(shù)有不同的解釋。串“ 0 0 1 2 3 1”將視為一個六位數(shù)字的值并解釋為D ATE 的“2 0 0 0 - 1 2 - 3 1”和D ATETIME 的“2000-12-31 00:00:00”。而數(shù)0 0 1 2 3 1被認(rèn)為1 2 3 1,這樣的解釋就有問題了。這種情形最好使用串值,或者如果要使用數(shù)值的話,應(yīng)該用完全限定的值(即, D ATE 用2 0 0 0 1 2 3 1,D ATETIME 用2 0 0 0 1 2 3 1 0 0 0 0)。通常,在D AT E、D ATETIME 和T I M E S TAMP 類型之間可以自由地賦值,但是應(yīng)該記住以下一些限制:
■ 如果將D ATETIME 或T I M E S TAMP 值賦給D AT E,則時間部分被刪除。
■ 如果將D ATE 值賦給D ATETIME 或T I M E S TA M P,結(jié)果值的時間部分被設(shè)置為零。
■ 各種類型具有不同的取值范圍。T I M E S TAMP 的取值范圍更受限制( 1970 到2 0 3 7),因此,比方說,不能將1970 年以前的DATETIME 值賦給T I M E S TAMP 并得到合理的結(jié)果。也不能將2037 以后的值賦給TIMES TAMP。MySQL 提供了許多處理日期和時間值的函數(shù)。要了解更詳細(xì)的信息請參閱附錄C。
6. 歧義年份值的理解
對于所有包括年份部分的日期和時間類型( DATE、DATE TIME、TIME STAMP、YEAR),MySQL將兩位數(shù)字的年份轉(zhuǎn)換為四位數(shù)字的年份。這個轉(zhuǎn)換根據(jù)下列規(guī)則進(jìn)行(在MySQL4.0 中,這些規(guī)則稍有改動,其中69 將轉(zhuǎn)換為1969 而不是2069。這是根據(jù)X/Open UNIX 標(biāo)準(zhǔn)規(guī)定的規(guī)則作出的改動):
■ 00 到69 的年份值轉(zhuǎn)換為2000 到2069。
■ 70 到99 的年份值轉(zhuǎn)換為1970 到1999。
通過將不同的兩位數(shù)字值賦給一個YEAR 列然后進(jìn)行檢索,可很容易地看到這些規(guī)則的效果。下面是檢索程序:
請注意,00 轉(zhuǎn)換為0000 而不是2 0 0 0。這是因?yàn)? 是YEAR 類型的一個完全合法的值;如果插入一個數(shù)值,得到的就是這個結(jié)果。要得到2 0 0 0,應(yīng)該插入串“ 0”或“0 0”??赏ㄟ^C O N C AT( ) 插入YEAR 值來保證MySQL 得到一個串而不是數(shù)。C O N C AT( ) 函數(shù)不管其參數(shù)是串或數(shù)值,都返回一個串結(jié)果。請記住,將兩位數(shù)字的年份值轉(zhuǎn)換為四位數(shù)字的年份值的規(guī)則只產(chǎn)生一種結(jié)果。在未給
定世紀(jì)的情況下,MySQL 沒有辦法肯定兩位數(shù)字的年份的含義。如果MySQL 的轉(zhuǎn)換規(guī)則不能得出您所希望的值,解決的方法很簡單:即用四位數(shù)字輸入年份值。MySQL 有千年蟲問題嗎?MySQL 自身是沒有2000 年問題的,因?yàn)樗趦?nèi)部是按四位數(shù)年份存儲日期值的,并且由用戶負(fù)責(zé)提供恰當(dāng)?shù)娜掌谥?。兩位?shù)字年份解釋的實(shí)際問題不是MySQL 帶來的,而是由于有的人想省事,輸入歧義數(shù)據(jù)所引起的問題。如果您愿意冒險,可以繼續(xù)這樣做。在您冒險的時候,MySQL 的猜測規(guī)則是可以使用的。但要意識到,很多時候您確實(shí)需要輸入四位數(shù)字的年份。例如, p r e s i d e n t表列出了1700 年以來的美國總統(tǒng),所以在此表中錄入出生與死亡日期需要四位的年份值。這些列中的年份值跨了好幾個世紀(jì),因此,讓MySQL 從兩位數(shù)字的年份去猜測是哪個世紀(jì)是不可能的。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
MySQL數(shù)據(jù)類型和常用字段屬性總結(jié)
MySQL數(shù)據(jù)庫基礎(chǔ)教程
Mysql,SqlServer,Oracle,sqlite 主鍵自動增長的設(shè)置
mysql?LAST_INSERT_ID詳解
mysql的auto_increment列
MySQL的表定義語法
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服