4.1 數據類型分類
分類 | 數據類型 | 說明 |
數值類型 | BIT(M) | 位類型。M指定位數,默認值1,范圍1 - 64 |
TINYINT [UNSIGNED] | 帶符號的范圍 -128 ~ 127,無符號范圍0 ~ 255,默認有符號 | |
BOOL | 使用0和1表示真和假 | |
SMALLINT [UNSIGNED] | 帶符號是次方到,無符號是 | |
INT [UNSIGNED] | 帶符號是次方到,無符號是 | |
BIGINT [UNSIGNED] | 帶符號是次方到,無符號是 | |
FLOAT(M,D)[UNSIGNED] | M指定顯示長度,D指定小數位數,占用4字節 | |
DOUBLE[(M,D)][UNSIGNED] | 表示比float精度更大的小數,占用空間8字節 | |
DECIMAL(M,D)[UNSIGNED] | 定點數,M指定長度,D表示小數點的位數 | |
文本、二進制類型 | CHAR(size) | 固定長度字符串,最大255 |
文本、二進制類型 | VARCHAR(SIZE) | 可變長度字符串,最大長度65535 |
文本、二進制類型 | BLOB | 二進制數據 |
文本、二進制類型 | TEXT | 大文本,不支持全文索引,不支持默認值 |
時間日期類型 | DATE/DATETIME/TIMESTAMP | 日期類型(yyyy - nn - dd)、(yyyy - n - d hh:mm:ss),timestamp時間戳 |
String類型 | ENUM類型 | ENUM是一個字符串對象,其值來自表創建時在列規定中顯示枚舉的一列值 |
SET類型 | SET是一個字符串對象,可以有零或多個值,其值來自表創建時規定的允許的一列值。指定包括多個set成員的set列值時各成員之間用逗號間隔開,set成員值本身不能包含逗號 |
4.2 數值類型
類型 | 字節 | 最小值(帶符號的/無符號的) | 最大值(帶符號的/無符號的) |
TINYINT | 1 | -128 / 0 | 127 / 255 |
SMALLINT | 2 | -32768 / 0 | 32767 / 65535 |
MEDIUMINT | 3 | -8388608 / 0 | 8388607 / 16777215 |
INT | 4 | -2147483648 / 0 | 2147483647 / 4294967295 |
BIGINT | 8 | -9223372036854775808 / 0 | 9223372036854775807 / 18446744073709551615 |
4.2.1 tinyint類型
- 數值越界測試
mysql> create table tt1(num tinyint); Query OK, 0 rows affected (0.02 sec) mysql> insert into tt1 values(1); Query OK, 1 row affected (0.00 sec) mysql> insert into tt1 values(128); -- 越界插入,報錯 ERROR 1264 (22003): Out of range value for column 'num' at row 1 mysql> select * from tt1; | num | +-----+ | 1 | +-----+ 1 row in set (0.00 sec)
說明:在MySQL中,整型可以指定是有符號的和無符號的,默認是有符號的。可以通過UNSIGNED來說明某個字段是無符號的。2. 無符號案例
mysql> create table tt2(num tinyint unsigned); mysql> insert into tt2 values(-1); -- 無符號,范圍是: 0 - 255 ERROR 1264 (22003): Out of range value for column 'num' at row 1 mysql> insert into tt2 values(255); Query OK, 1 row affected (0.02 sec) mysql> select * from tt2; | num | +-----+ | 255 | +-----+ 1 row in set (0.00 sec)
注意:盡量不使用unsigned,對于int類型可能存放不下的數據,int unsigned同樣可能存放不下,與其如此,還不如設計時,將int類型提升為bigint類型。
4.2.2 bit類型
- 基本語法:bit[(M)] :位字段類型。M表示每個值的位數,范圍從1到64。如果M被忽略,默認為1。
- 舉例
mysql> create table tt4 ( id int, a bit(8)); Query OK, 0 rows affected (0.01 sec) mysql> insert into tt4 values(10, 10); Query OK, 1 row affected (0.01 sec) mysql> select * from tt4; #發現很怪異的現象,a的數據10沒有出現 | id | a | +----+---+ | 10 | | +----+---+ 1 row in set (0.00 sec)
- bit使用的注意事項:bit字段在顯示時,是按照ASCII碼對應的值顯示。
mysql> insert into tt4 values(65, 65); mysql> select * from tt4; | id | a | +----+---+ | 10 | | | 65 | A | +----+---+
如果我們有這樣的值,只存放0或1,這時可以定義bit(1)。這樣可以節省空間。
mysql> create table tt5(gender bit(1)); mysql> insert into tt5 values(0); Query OK, 1 row affected (0.00 sec) mysql> insert into tt5 values(1); Query OK, 1 row affected (0.00 sec) mysql> insert into tt5 values(2); -- 當插入2時,已經越界了 ERROR 1406 (22001): Data too long for column 'gender' at row 1
4.2.3 小數類型
4.2.3.1 float
- 語法:float[(m, d)] [unsigned] :M指定顯示長度,d指定小數位數,占用空間4個字節。
- 案例:小數float(4,2)表示的范圍是 -99.99 ~ 99.99,MySQL在保存值時會進行四舍五入。
mysql> create table tt6(id int, salary float(4,2)); Query OK, 0 rows affected (0.01 sec) mysql> insert into tt6 values(100, -99.99); Query OK, 1 row affected (0.00 sec) mysql> insert into tt6 values(101, -99.991); #多的這一點被拿掉了 Query OK, 1 row affected (0.00 sec) mysql> select * from tt6; | id | salary | +-----+--------+ | 100 | -99.99 | | 101 | -99.99 | +-----+--------+ 2 rows in set (0.00 sec)
問題:當我們的float(4,2)如果是一個有符號的,則表示范圍是 -99.99 ~ 99.99,如果float(6,3),請同學們說說范圍是多少?3. 案例:如果定義的是float(4,2) unsigned 這時,因為把它指定為無符號的數,范圍是0 ~ 99.99。
mysql> create table tt7(id int, salary float(4,2) unsigned); Query OK, 0 rows affected (0.01 sec) mysql> insert into tt7 values(100, -0.1); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> show warnings; | Level | Code | Message | +-------+------+---------------------------+ | Warning | 1264 | Out of range value for column 'salary' at row 1 | +-------+------+---------------------------+ 1 row in set (0.00 sec) mysql> insert into tt7 values(100, -0); Query OK, 1 row affected (0.00 sec) mysql> insert into tt7 values(100, 99.99); Query OK, 1 row affected (0.00 sec)
4.2.3.2 decimal
- 語法:decimal(m, d) [unsigned] :定點數m指定長度,d表示小數點的位數。
- decimal(5,2) 表示的范圍是 -999.99 ~ 999.99;decimal(5,2) unsigned 表示的范圍0 ~ 999.99。
- decimal和float很像,但是有區別:float和decimal表示的精度不一樣。
- 存在精度損失, 只不過相比于 float 來說精度更高.
mysql> create table tt8 ( id int, salary float(10,8), salary2 decimal(10,8)); mysql> insert into tt8 values(100,23.12345612, 23.12345612); Query OK, 1 row affected (0.00 sec) mysql> select * from tt8; | id | salary | salary2 | +-----+-----------+-----------+ | 100 | 23.12345695 | 23.12345612 | # 發現decimal的精度更準確,因此如果我們希望某個數據表示高精度,選擇decimal +-----+-----------+-----------+
說明:float表示的精度大約是7位。decimal整數最大位數m為65。支持小數最大位數d是30。如果d被省略,默認為0。如果m被省略, 默認是10。
建議:如果希望小數的精度高,推薦使用decimal。
4.3 字符串類型
4.3.1 char
- 語法:char(L) :固定長度字符串,L是可以存儲的長度,單位為字符,最大長度值可以為255。
- 案例(char)
mysql> create table tt9(id int, name char(2)); Query OK, 0 rows affected (0.00 sec) mysql> insert into tt9 values(100, 'ab'); Query OK, 1 row affected (0.00 sec) mysql> insert into tt9 values(101, '中國'); Query OK, 1 row affected (0.00 sec) mysql> select * from tt9; | id | name | +-----+------+ | 100 | ab | | 101 | 中國 | +-----+------+
說明: char(2) 表示可以存放兩個字符,可以是字母或漢字,但是不能超過2個,最多只能是255。
mysql> create table tt10(id int ,name char(256)); ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use BLOB or TEXT instead
4.3.2 varchar
- 語法:varchar(L) :可變長度字符串,L表示字符長度,最大長度65535個字節。
- 案例
mysql> create table tt10(id int ,name varchar(6)); --表示這里可以存放6個字符 mysql> insert into tt10 values(100, 'hello'); mysql> insert into tt10 values(100, '我愛你,中國'); mysql> select * from tt10; | id | name | +-----+------------------+ | 100 | hello | | 100 | 我愛你,中國 | +-----+------------------+
說明:關于varchar(len),len到底是多大,這個len值,和表的編碼密切相關。varchar長度可以指定為0到65535之間的值,但是有1 - 3個字節用于記錄數據大小,所以說有效字節數是65532。當我們的表的編碼是utf8時,varchar(n)的參數n最大值是65532 / 3 = 21844[因為utf8中,一個字符占用3個字節],如果編碼是 gbk,varchar(n)的參數n最大是65532 / 2 = 32766(因為gbk中,一個字符占用2字節)。
mysql> create table tt11(name varchar(21845))charset=utf8; --驗證了utf8確實是不能超過21844 ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs mysql> create table tt11(name varchar(21844)) charset=utf8; Query OK, 0 rows affected (0.01 sec)
4.3.3 char和varchar比較
實際存儲 | char(4) | varchar(4) | char占用字節 | varchar占用字節 |
abcd | abcd | abcd | 4 * 3 = 12 | 4 * 3 + 1 = 13 |
A | A | A | 4 * 3 = 12 | 1 * 3 + 1 = 4 |
Abcde | × | × | 數據超過長度 | 數據超過長度 |
如何選擇定長或變長字符串?
- 如果數據確定長度都一樣,就使用定長(char),比如:身份證,手機號,md5。
- 如果數據長度有變化,就使用變長(varchar),比如:名字,地址,但是你要保證最長的能存得進去。
- 定長的磁盤空間比較浪費,但是效率高。
- 變長的磁盤空間比較節省,但是效率低。
- 定長的意義是,直接開辟好對應的空間。
- 變長的意義是,在不超過自定義范圍的情況下,用多少,開辟多少。
4.4 日期和時間類型
常用的日期有如下三個:
- date :日期'yyyy - mm - dd' ,占用三字節。
- datetime :時間日期格式 'yyyy - mm - dd HH:ii:ss' 表示范圍從1000到9999 ,占用八字節。
- timestamp :時間戳,從1970年開始的 yyyy - mm - dd HH:ii:ss 格式和datetime完全一致,占用四字節。
案例
- 創建表
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp); Query OK, 0 rows affected (0.01 sec)
- 插入數據
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1'); --插入兩種時間 Query OK, 1 row affected (0.00 sec) mysql> select * from birthday; | t1 | t2 | t3 | +------------+--------------------+--------------------+ | 1997-07-01 | 2008-08-08 12:01:01 | 2017-11-12 18:28:55 | --添加數據時,時間戳自動補上當前時間 +------------+--------------------+--------------------+
- 更新數據
mysql> update birthday set t1='2000-1-1'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from birthday; | t1 | t2 | t3 | +------------+--------------------+--------------------+ | 2000-01-01 | 2008-08-08 12:01:01 | 2017-11-12 18:32:09 | -- 更新數據,時間戳會更新成當前時間 +------------+--------------------+--------------------+
4.5 enum和set
- 語法
- enum:枚舉,“單選”類型;enum('選項1','選項2','選項3',...)。該設定只是提供了若干個選項的值,最終一個單元格中,實際只存儲了其中一個值;而且出于效率考慮,這些值實際存儲的是“數字”,因為這些選項的每個選項值依次對應如下數字:1,2,3,....最多65535個;當我們添加枚舉值時,也可以添加對應的數字編號。
- set:集合,“多選”類型;set('選項值1','選項值2','選項值3', ...)。該設定只是提供了若干個選項的值,最終一個單元格中,設計可存儲了其中任意多個值;而且出于效率考慮,這些值實際存儲的是“數字”,因為這些選項的每個選項值依次對應如下數字:1,2,4,8,16,32,....最多64個。說明:不建議在添加枚舉值、集合值的時候采用數字的方式,因為不利于閱讀。
- 案例:有一個調查表votes,需要調查人的喜好,比如(登山,游泳,籃球,武術)中去選擇(可以多選),(男,女)[單選]。
mysql> create table votes( -> username varchar(30), -> hobby set('登山','游泳','籃球','武術'), --注意:使用數字標識每個愛好的時候,想想Linux權限,采用比特位位置來和set中的愛好對應起來 -> gender enum('男','女')); --注意:使用數字標識的時候,就是正常的數組下標 Query OK, 0 rows affected (0.02 sec)
- 插入數據
insert into votes values('雷鋒', '登山,武術', '男'); insert into votes values('Juse','登山,武術',2);
- 查詢數據
select * from votes where gender=2;
結果:
| username | hobby | gender | | Juse | 登山,武術 |女
有如下數據,想查找所有喜歡登山的人:
| username | hobby | gender | | 雷鋒 | 登山,武術 | 男 | | Juse | 登山,武術 | 女 | | LiLei | 登山 | 男 | | LiLei | 籃球 | 男 | | HanMeiMei | 游泳 | 女 |
使用如下查詢語句:
mysql> select * from votes where hobby='登山';
結果:
| username | hobby | gender | | LiLei | 登山 | 男 |
不能查詢出所有愛好為登山的人。5. 集合查詢使用 find_in_set 函數:find_in_set(sub,str_list) :如果sub在str_list中,則返回下標;如果不在,返回0;str_list用逗號分隔的字符串。
mysql> select find_in_set('a', 'a,b,c');
結果:
| find_in_set('a', 'a,b,c') | | 1 |
mysql> select find_in_set('d', 'a,b,c');
結果:
| find_in_set('d', 'a,b,c') | | 0 |
查詢愛好登山的人:
mysql> select * from votes where find_in_set('登山', hobby);
結果:
| username | hobby | gender | | 雷鋒 | 登山,武術 | 男 | | Juse | 登山,武術 | 女 | | LiLei | 登山 | 男 |
對于 enum(枚舉, 單選) 和 set(集合, 多選) 可以用 數字進行篩選.