MySQL權威指南讀書筆記,第二章:MYSQL數據庫裏面的數據



用想用好MYSQL,就必須透徹理解MYSQL是如何看待和處理數據的。本章主要討論了兩個問題:一是SQL所能處理的數據值的類型;二是這些數據類型在實際應用中需要注意的問題。
首先我們看看mysql能夠支持的數據類型,和其它的數據庫一樣,我們可以處理各種數值(整型,浮點),字符串型,日期/時間型,NULL值等等。大家在使用的需要注意不同類型的數值的格式是不一樣的。在這裏,對字符串的處理有一個比較特殊的地方大家需要理解。因爲字符串兩端是需要用引號(單引號,雙引號)括起來的,但是如果字符串本身裏面也包括了引號(單引號,雙引號),我們應該怎麼辦呢。這時就必須用以下三種方法之一來標識這個特殊的字符串。
1, 如果字符串內部的引號字符與字符串兩端的引號字符相同,則雙寫該引號
‘I can’’t’
“He said,””I told you so, “”’
2, 用與字符串內部的引號字符不同的引號把該字符串引起來,此時,就不用雙寫字符串內部的引號了
“I can’t”
‘He said,”I told you so,”’
3, 用反斜槓對字符串內部的引號字符進行轉義,此時與字符串兩端的引號無關
‘I can/’t’
“He said,/”I told you so,/””

下面我們看數據列類型,真的很奇怪,數據列裏面放數據,兩者類型不相同。事實上,把數據列類型叫做列類型也許更合適一些,數據類型只是一種含義廣泛的分類方法,比如:數值,字符串等等。而列類型是對一個給定的數據列裏面的值有哪些具體特點的準確描述。比如smallint或varchar(10)等。也就是說,數據列類型決定了mysql如何對待這些數據,你不能把abc放到一個數值列裏面!如果你給你的數據找到一個合適的位置,下列問題時必須考慮的:
需要把哪些種類的數值保存到數據表裏面?
這種類型的值要佔用多少存儲空間?
這種類型的值長度是否固定不變?
這種類型的值如何進行比較和排序?
這種類型的值可以用null值嗎?
如何對這種類型的值進行索引呢?
當你對這些問題都能心中有數的時候,就可以選擇具體的列類型了,當然,每一種列類型都有相應的特徵表格大家可以查詢。需要注意的是這幾點:
1,顯示寬度
整數列的顯示寬度與mysql需要用多少個字符來顯示該列數值,與該整數需要的存儲空間的大小都沒有關係,比如,不管設定了顯示寬度是多少個字符,bigint都要佔用8個字節。
2,截短處理
數值類型列的取值範圍是由它的具體類型決定的。如果想把一個超出列取值範圍的值插入到各個列中,mysql會截短這個值,會先把這個值替換爲該數據列取值範圍的上限或下限,然後插入,這種截短僅與這個列的取值範圍有關,與該列的顯示寬度無關。比如說:把99999插入到一個類型爲smallint(3)的數據列裏面,就會被截短爲32767
3,前導0的問題
如果想讓某列裏面的值都能全部整齊的按所定義的顯示寬度顯示出來,就需要使用zerofill屬性,就可以在數值前面加入不定數目的0來顯示數值,這個功能有些情況下很有用。但有一點需要注意,如果一個數值長度大於定義的顯示寬度,這個數值也會正常顯示,此時不受顯示寬度的限制。
4,enum和set
需要記住,這兩種數據列的列定義裏面都要有一個列表,列表裏面的元素就是該列的合法取值。如果你試圖把一個不在這個列表裏面數據放入本列,它就會被轉換爲空字符串!
5,日期和時間
在許多情況下,希望能夠在數據列裏面創建一條記錄的時候可以記錄當時的日期和時間。還希望這個時間值不會因爲以後的操作而改變,但令人遺憾的是,目前仍然沒有一種mysql列類型能夠直接滿足這個需要,現在我們一般用兩個辦法來解決這個問題:
1,使用一個timestamp數據列,在需要創建一條新紀錄的時候,把這個timestamp數據列設置爲null.也就是把它初始化爲當前的日期和實踐.
Insert into table_name (ts_col,…) values (null,…);
在以後對這條紀錄進行修改的時候,要用這個列裏面的現有數據對它進行賦值.這種明確賦值的做法將抑制住mysql 的時間戳機制,讓timestamp數據列裏面的值不會自動改變.
Update table_name set ts_col=ts_col where …
2,使用一個datetime數據列,在需要創建一條新紀錄的時候,用now() 函數來初始化這個數據列:
insert into table_name (dt_col,…) values (now(),…);
以後對這條紀錄進行修改的時候,不要碰這個數據列.
Update table_name set … anything but dt_col where …

關於年份的轉換問題
如果你把一個兩位數的年份值插入到一個year數據列裏面, mysql 會自動地按照一下規則來進行轉換:
年份值 00-69 轉換爲 2000-2069
年份值 70-99 轉換爲 1970-1999
需要注意的是00這個年份,如果你執行:
insert into table_name values (00) 其結果就會變成 0000
因此,如果想使用一個沒有世紀部分的值,結果得到2000年,就必須是用字符串格式 ’00’ 如果想讓mysql 把一個向year 數據列插入的值看作字符串而不是數值,就應該用 concat()函數把這個值轉化爲字符串,無論輸出參數是一個字符串還是一個數值, concat() 都會返回一個字符串.

序列和編號
作者之所以把序列和編號的問題單獨拿出來講解,是因爲許多應用程序都需要一個獨一無二的編號來把一條記錄和其他的分別開來.
在mysql 裏面,這種獨一無二的編號是通過數據列的auto_increment 屬性而自動生成一組序列編號的辦法來實現的.需要我們首先知道的是, mysql目前支持多種數據表類型.不同的數據表類型對於auto_increment 屬性的處理機制是不一樣的!所以我們不僅需要掌握有關auto_increment 屬性的基本知識,還需要熟悉這種機制在各種的數據表類型中的差異.
Mysql 3.23以前的版本僅僅支持比較基礎的ISAM 數據表類型,在後來的版本中,其他幾種數據表類型也逐步加了進來.包括 MyISAM 和 HEAP 類型等等.現在我們使用mysql的時候默認建立的數據表都是比較先進的MyISAM類型.我們先看比較基礎的IASM表類型是如何看待數據列的auto_increment 屬性.?
A 如果試圖把一個null 值插入到一個auto_increment 數據列裏面,Mysql會自動生成一個序列編號並插入,一般從1開始,依次遞增
B 不要把0插入auto_increment 數據列裏面,我們不推薦這這樣做.
C如果在需要創建一條新紀錄的時候,對auto_increment 數據列明確制定了一個數,會有兩種情況存在:1,某個紀錄已經使用了這個數,此時Mysql 會報告錯誤.2,如果沒有紀錄使用這個數,那麼紀錄正常插入,以後再插入的新紀錄就會以這個編號+1開始!也就是說,我們可以人爲地”跳過”一些編號,舉例來說,如果插入一個”假”紀錄,編號爲999 那麼以後的紀錄就會從1000開始.然後我們就可以刪除”假”紀錄了.這是個簡單的技巧.
D 如果刪除了編號最大的紀錄.再插入新紀錄的時候仍然會使用這個編號!這是ISAM表本身的特點,也就是說,如果把數據表裏面的紀錄全部幹掉的話,新紀錄編號將從1開始
E last_insert_id() 函數能夠返回編號序列中最後一個生成的編號.在某些情況下,我們可以利用這個函數取得當前數據表中最後一個生成的編號.

下面要說的是Mysql 裏面的,目前大部分用戶使用的 MyISAM表類型對auto_increment 數據屬性的處理方法,可以看到,這種新的表類型有更大的靈活性,消除了原始的IASM標在處理序列和編號方面的許多缺陷!下面我們看:
A 在MyIASM表裏面,一個自動生成的序列編號將嚴格地依次遞增,即使被刪掉也不會被再次使用!
B 可以在建立數據表的時候,使用 auto_increment=n 選項爲序列編號明確地設定一個初始值
C 可以用alter table 隨時改變MyISAM表中auto_increment的開始值,比如,下面這條命令會讓序列編號從2000開始

其他注意事項
1,Mysql 提供auto_increment的主要目的是生成一個正整數數據列,所以我們可以把該列聲明爲unsigned ,這樣能夠使用的編號範圍就多了一倍
2, auto_increment 屬性仍然受到具體的數據列的取值範圍的限制,比如一個tinyint數據列,編號最大值也只能是127
3,清除一個表的全部內容會讓序列從1開始重新生成.

最後的問題
當我們打算創建一個數據表的時候,面對這麼多的數據列屬性,如果做出正確的選擇?
A這個數據列將用來存放哪一種數據?
這是我們第一個需要考慮的問題,一般說來,這個問題的答案似乎很直觀:把數值放到數據列裏面;把字符串放到字符串列裏面;如果是整數就用整數列,如果有小數就用浮點類型。但是,事情往往不是這麼簡單,只有洞察有關數據的本質,才能明智地選擇出最佳類型,有時候的結論往往是這樣:最不適合人類閱讀和理解的方案往往是最適合數據庫的!這是不是很有趣,總之,對數據的全面把握纔是選擇數據列的關鍵所在。大家在學習過程中慢慢的體會這一點吧!

B數據值是否都在某個具體的範圍內?
在第一章,我們爲考試積分項目創建了一個名爲score 的數據表,其中有一個用來記錄考試和測驗成績的score 數據列,當時我們使用了int 類型,現在我們考慮到了對於考試來說,成績一般都在0-100之間,因此我們用 tinyint unsigned 是不是更合適呢?但是如果有一種特殊情況,那就是校方會用-1來表示某個學生因病沒有來考試,這時unsigned 就不行了
C有沒有性能和效率方面的問題?
一般來說:
數值操作比字符串快
近可能地使用enum類型,因爲這種類型在MySQL內部是用數值表示的,速度較快!
小類型的處理速度比大類型快

D打算如何對有關數據進行比較?
E是否要在某個數據列商建立索引?
這兩個問題往往看似簡單,但對於比較特殊的應用來說值得相當關注!

有關數據類型轉換的問題
這個問題是很重要的!尤其對於那些用來刪改數據記錄的delete和update語句,必須確保這些語句只能施加在想對之進行操作的那些記錄上!舉例來說,假設某個數據表中有這麼一個char數據列
‘abc’
‘def’
‘00’
‘jk0’
看這個命令 delete from table_name where char=00
我們的本意可能是想把包含有00那條記錄刪掉,可實際上本命令執行之後會把所有的記錄全部趕掉!原因就在於MySQL把00當作了一個數值(字符串和數值比較時,比較操作將把他的兩個操作數都當作數值來看待,這種情況下,所有的字符串都不可避免的變成了0)
所以我們在執行delete語句之前一定要先用select 檢查一下 where 帶來的結論。


下面是最常見的類型轉換功能,大家好好學學
1) 把數據加上一個0或0.0 能把它強制轉換爲數值型
2) floor函數會把浮點數強制轉換爲整數
3) 給一個整數加上一個0.0會強制轉換爲浮點數
4) concat函數能把任何類型強制轉換爲字符串
5) hex函數能把字符串強制轉換爲十六進制數
6) ascii函數能把字符轉換爲ascii碼
7) data_add函數能夠把字符串或者數值轉換爲日期和時間值
8) 給日期和時間值加上一個0,可以強制轉換爲數值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章