MySQL的數據類型分爲五大類: 數值類型、字符串類型、時間類型、空間類型和json類型(5.7新增)。每一個大類下面又有不少具體類型,它們的不一樣主要體如今長度範圍、精度和須要的物理空間(磁盤和內存)。html
注: 本文講述基於MySQL5.7, 有些內容5.7 版本如下的可能不適用,如json類型mysql
數值類型只是個大類,它下面還有BIT、INT、FLOAT、DECIMAL等具體分類。sql
MySQL對數值類型的定義有以下約定:
1.符號[]表示裏面的參數是可選的shell
2.對於整數類型,M表示該類型顯示的最大長度,與實際存儲的範圍無關;對於實數類型(Float、Double、Decimal),M表示該類型存儲的最大長度json
3.對於整數類型,有SIGNED和UNSIGNED兩種屬性,默認屬性爲SIGNED,可以存儲負數。若是屬性爲UNSIGNED,則不容許存儲負數。若是沒有存儲負數的需求,UNSIGNED屬性的類型可使存儲的範圍提升一倍。好比TINYINT的存儲範圍是 -128-127,而UNSIGNED TINYINT 的存儲範圍是0-255。segmentfault
4.若是定義一個類型時指定了ZEROFILL屬性,則該類型默認帶有UNSIGNED屬性,即不能存儲負數bash
5.「SERIAL」 類型是 「BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE」 的別名。測試
6.「serial default value「 是 」NOT NULL AUTO_INCREMENT UNIQUE」 的別名ui
# 實驗1
create table mysql_test_serial (
id int(11) not null primary key,
single_serial serial -- 因爲主鍵id沒有指定自增,因此容許添加
);
create table mysql_test_serial2 (
id int(11) not null primary key,
serial_attribute int(11) serial default value, -- 因爲主鍵id沒有指定自增,因此容許添加
zerofill_attribute int(11) zerofill not null default 0, -- 測試是否默認帶有unsigned屬性
unsigned_attribute int(11) unsigned not null default 0 -- 定義帶有unsigned屬性的類型
);
複製代碼
實驗1效果圖:
編碼
位數據類型,M表示存儲的值的位數,範圍從1-64,默認值是1
# 實驗2: 注意位數據類型的加減,須要謹慎使用
create table bittest (
a bit(8)
)
insert into bittest set a=b'00111001';
# a是ASCII碼爲57的字符「9」, 可是a+0的數字加減場景中,獲得的是57。
mysql> select a, a+0 from bittest;
+------+------+
| a | a+0 |
+------+------+
| 9 | 57 |
+------+------+
複製代碼
TINYINT(1)類型的別名,它有兩個值,TRUE和FALSE。
該類型的邏輯判斷方式跟常見的不太同樣,詳情參見:dev.mysql.com/doc/refman/…
存儲的值爲整數,包含五個子類:TINYINT / SMALLINT / INT / MEDIUMINT / BIGINT, 存儲的範圍見下圖:
INT(11) 表示的含義:
前面講過,若是是整數類型,括號裏面的11,只表示該類型顯示的最大長度,與實際存儲的範圍無關,可經過實驗3證實。
# 實驗3
# 建立表(必須加上zerofill,才能看到有沒有補零)
create table test_int_length (
id int(11) not null primary key,
int_four1 int(4) not null default 0,
int_four2 int(4) zerofill not null default 0,
int_eleven int(11) zerofill not null default 0
);
# 插入數據
insert into test_int_length (id, int_four1, int_four2) values (1, 1, 1);
insert into test_int_length (id, int_four1, int_four2) values (2, 100000, 100000);
# 能夠看到當插入數據爲1, 不足4位,會自動補零
mysql> select * from test_int_length;
+----+-----------+-----------+-------------+
| id | int_four1 | int_four2 | int_eleven |
+----+-----------+-----------+-------------+
| 1 | 1 | 0001 | 00000000000 |
| 2 | 100000 | 100000 | 00000000000 |
+----+-----------+-----------+-------------+
2 rows in set (0.00 sec)
複製代碼
MySQL提供兩種類型(FLOAT和DOUBLE)來存儲浮點數(小數),當存儲的類型在規定的範圍內時,這兩種類型存儲的值是精確的,但若是超過規定的範圍,則超過的部分會被截斷和四捨五入,致使精度缺失。
爲了使存儲的浮點數不會丟失精度,MySQL提供了DECIMAL這種類型。其中,M表示總位數(不包括小數點和負數前面的橫槓),D表示小數點後的位數。
M最大值爲65,默認值是10; D最大值是30,默認值是0
DEC VS NUMERIC VS FIXED
可能有時候咱們會看到這三種類型,其實這三種類型都是DECIMAL的別名。
注: 除了能夠用DECIMAL類型來保證存儲的小數是精確的,還有另一種取巧的辦法,使用整數類型存儲,在最終顯示的時候除以對應的值便可,好比1.777 = 1777 / 1000。
單精度浮點型。存儲的範圍爲(-3.402823466E+38,-1.175494351E-38), 0, 和 (1.175494351E-38 to 3.402823466E+38),由於不可能存儲無限位小數,因此只能無限接近於0。
M是總位數,D是小數點後的位數。若是省略M和D,則將值存儲到硬件容許的極限。單精度浮點數的精度約爲小數點後7位。
FLOAT(p)
一種特殊的表現形式,當p的範圍是0-24時,表示使用FLOAT類型;當p的範圍是25-63時,表示使用DOUBLE類型。
單精度浮點型。存儲的範圍爲(-1.7976931348623157E+308,-2.2250738585072014E-308), 0, 和 (2.2250738585072014E-308 to 1.7976931348623157E+308)
M是總位數,D是小數點後的位數。若是省略M和D,則將值存儲到硬件容許的極限。單精度浮點數的精度約爲小數點後15位。
REAL / DOUBLE PRECISION
這兩種類型是DOUBLE類型的別名,不過若是「REAL_AS_FLOAT」這個參數設置爲enabled, REAL表明的是FLOAT類型。
MySQL的時間類型包含五個具體類型: DATE, TIME, DATETIME, TIMESTAMP, and YEAR。其中,TIME、TIMESTAMP、DATETIME容許精確到微妙,即小數點後6位。
fractional seconds strorage表示小數點後的數字佔用的字節
舉例: TIME(0), TIME(2), TIME(4) 和 TIME(6) 分別佔用 3, 4, 5, and 6 bytes。
支持的範圍 '1000-01-01' - '9999-12-31'。雖然DATE類型使用'YYYY-MM-DD'格式展現,可是它支持數值或者字符串的輸入方式,舉例以下。
# 建表
create table datetest (
date1 DATE,
datetime1 DATETIME,
datetime2 DATETIME(3),
);
# 插入數據(數值或者字符串)
mysql> insert into datetest set date1=20191128;
mysql> insert into datetest set date1='20191128';
mysql> insert into datetest set date1='2019-11-28';
# 插入當前時間
mysql> insert into datetest set date1=CURDATE();
複製代碼
支持的範圍 '1000-01-01 00:00:00.000000' - '9999-12-31 23:59:59.999999', 默認值是NULL,一樣也支持數值或者字符串的輸入方式,舉例以下。
因爲DATETIME沒有時區的概念,默認時間是UTC時間,若是想要改成北京時間,則須要修改time_zone參數
查看:
show global variables like '%time_zone%';
修改:
blog.csdn.net/iris_xuting…
實驗:
create table datetest (
date1 DATE,
datetime1 DATETIME,
datetime2 DATETIME(3),
);
# 插入數據(數值或者字符串)
mysql> insert into datetest set datetime1='2019-11-28 12:00:00';
mysql> insert into datetest set datetime1=20191128120000;
# 插入當前時間
mysql> insert into datetest set datetime1=CURDATE();
# datetime和timestamp均可以設置自動初始化和更新時間
create table datetest2 (
datetime1 DATETIME DEFAULT CURRENT_TIMESTAMP, -- 只是自動初始化,當數據改變時時間不會改變
datetime2 DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 當數據改變時時間會隨之改變
datetime3 DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) -- 當指定精度時,DEFAULT 和 ON UPDATE也要指定相同精度
);
複製代碼
支持的範圍 '1970-01-01 00:00:01.000000' - '2038-01-19 03:14:07.999999', 這裏的時間範圍基於UTC時間。另外,TIMESTAMP列的默認值不能爲NULL。
須要注意的是,TIMESTAMP的表現形式基於 explicit_defaults_for_timestamp 參數,默認值是OFF(5.7版本),不開啓。
若是該參數爲ON,則類型爲TIMESTAMP的column不會自動初始化和更新時間。
若是該參數爲OFF且有多個列的類型都爲TIMESTAMP,只有第一個列的時間會自動更新,其餘列不會(除非加上 DEFAULT 和 ON UPDATE)
# 建立表
create table datetest3 (
id int(11) not null default 0,
timestamp1 TIMESTAMP,
timestamp2 TIMESTAMP not null default '2018-10-01 00:00:00'
);
# 測試
mysql> insert into datetest3 set id=1;
mysql> select * from datetest3;
+----+---------------------+---------------------+
| id | timestamp1 | timestamp2 |
+----+---------------------+---------------------+
| 1 | 2019-11-30 12:30:58 | 2018-10-01 00:00:00 |
+----+---------------------+---------------------+
複製代碼
TIMESTAMP的時間範圍爲何只到2038?
www.jianshu.com/p/b222dcc47…
TIMESTAMP的時區問題
www.cnblogs.com/gaogao67/p/…
www.cnblogs.com/deverz/p/98…
blog.csdn.net/sinat_26594…
segmentfault.com/a/119000001…
注:對於有夏令時的地區,本地時間等於UTC時間 + 時區偏移 + 夏令時偏移
支持的範圍 '-838:59:59.000000' - '838:59:59.000000', 這種類型通常比較少用,除非你只須要當天的時間。
存儲年份,通常也比較少用,除非你只須要存儲年份。
MySQL以前的版本還支持YEAR(2)類型,不過這個類型將在MySQL5.7.5中廢棄
MySQL的字符串類型包含如下具體類型: CHAR, VARCHAR, TEXT, ENUM和SET。
特性:
1.能夠單獨對類型爲字符串的列設置字符集(CHARSET / CHARACTER SET)
CREATE TABLE t
(
c1 VARCHAR(20) CHARSET utf8,
c2 TEXT CHARACTER SET latin1 COLLATE latin1_general_cs
);
複製代碼
2.能夠對整張表設置字符集
CREATE TABLE t2
(
c1 VARCHAR(20) CHARSET utf8,
c2 TEXT
) CHARSET utf8mb4;
mysql> show full columns from t2;
+-------+-------------+--------------------+------+-----+---------+
| Field | Type | Collation | Null | Key | Default |
+-------+-------------+--------------------+------+-----+---------+
| c1 | varchar(20) | utf8_general_ci | YES | | NULL |
| c2 | text | utf8mb4_general_ci | YES | | NULL |
+-------+-------------+--------------------+------+-----+---------+
複製代碼
3.字符集別名
ASCII ==> CHARACTER SET latin1
UNICODE ==> CHARACTER SET ucs2
4.二進制類型 VS 文本類型
blog.csdn.net/u014465934/…
該類型存儲的是定長字符串,與數值類型不一樣,M表示存儲的最大字符數, M的默認值爲1,最大值爲255。對於utf8字符集來講,一個字母和一個漢字都算是一個字符。
注: 這裏要注意存儲字符(characters)和存儲字節(bytes)的區別,好比CHAR(5), 它最大存儲5個字符,若是使用的是utf8字符集,存儲的字節是5 * 3字節=15字節。
create table char_test (
id int(11) not null default 0,
char1 char(10) charset utf8 not null default ''
);
-- 沒法插入,超出存儲範圍
insert into char_test set char1="abcdefghijkl";
insert into char_test set char1="一二三四五六七八九十十一";
-- 能夠插入
insert into char_test set char1="abcdefghij";
insert into char_test set char1="一二三四五六七八九十";
複製代碼
注: NCHAR、NATIONAL CHARACTER 是 CHAR CHARACTER SET utf8 的別名
該類型存儲的是非定長字符串,即有可能用1字節,2字節或者3字節等存儲一個字符。M也表示存儲的最大字符數,M的範圍是0-65535。
這裏也要注意下字節和字符的區別,同CHAR。
VARCHAR(255)的由來
1.雖然VARCHAR最大可以存儲65535個字符,但文檔同時也提到MySQL表的每一行也是有大小限制的,很是巧,這個數字是65535字節。
2.經過計算,若是varchar使用的是utf8字符集,則每一行存儲的最大字符數爲65535/3=21845; 若是使用utf8mb4,則最大字符數爲65535/4=16383。
但上面的計算方式實際上是一種理想化的計算,實際上還要減去一些額外的字節,有兩種計算方式: 1.若是包含一個字段id,且類型爲int,則存儲的字符爲(65535-1-2-4)/3 = 21843 字符。
2.若是不包含字段id,則存儲的字符爲(65535-1-2)/3 = 21844 字符。
那是否是就能夠定義varchar(21844)呢? 確實能夠,可是這樣不現實,由於你不僅這一列,其餘列也須要佔用字節。
3.varchar(255)的由來是由於InnoDB存儲引擎的表索引的前綴長度最長是767字節(bytes),原由是2^8×3-1。767表示3個字符最大佔用空間(utf8)。
因此,若是須要建索引,就不能超過 767 bytes,utf8編碼時 255*3=765bytes,偏偏是能建索引狀況下的最大值。
總而言之,255是一個是保證能少出錯的一個很好的默認值
# 實驗
mysql> create table varchar_test (
-> id int(11) not null default 0,
-> varchar1 varchar(21843) not null default ''
-> ) charset utf8;
Query OK, 0 rows affected (0.01 sec)
mysql> create table varchar_test1 (
-> id int(11) not null default 0,
-> varchar1 varchar(21844) not null default ''
-> ) charset utf8;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
mysql> create table varchar_test3 (
-> varchar1 varchar(21844) not null default ''
-> ) charset utf8;
Query OK, 0 rows affected (0.01 sec
複製代碼
CHAR VS VARCHAR
utf8 VS utf8mb4
與CHAR類型類似,但存儲的是二進制數據(2、8、十六進制也能夠),M表示存儲的最大字節,默認爲1
與VARCHAR類型類似,但存儲的是二進制數據,M表示存儲的最大字節。
該類型主要用於存儲比較大的二進制文件,包含四個具體類型: TINYBLOB / BLOB / MEDIUMBLOB / LONGBLOB。
該類型主要用於存儲比較大的文本,包含四個具體類型: TINYTEXT / TEXT / MEDIUMTEXT / LONGTEXT。
BLOB和TEXT存儲佔用的字節(L表示可存儲的字節,實際佔用的字節比L大,由於額外的字節被用於表示長度)
注:因爲類型較多,因此只講述了比較重要的類型,json類型有精力會繼續補充!(本文未經容許,不可轉載!)
參考:
segmentfault.com/q/101000000…