數據庫表由多列字段構成,每一個字段指定了不同的數據類型。指定字段得數據類型之後,也就決定了向字段插入的數據內容,例如,當要插入數值的時候,可以將他們存儲爲整數類型,也可以將它們存儲爲字符串類型;不同的數據類型也決定了mysql在存儲它們的時候使用的方式,以及在使用它們的時候選擇什麼運算符號進行運算。
1、MySQL數據類型介紹
MySQL支持多種數據類型,主要有數值類型、日期/時間類型和字符串類型。
(1)數值數據類型:包括整數類型TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT和浮點小數據類型FLOAT和DOUBLE、定點小數類型DECIMAL。
(2)日期/時間類型:包括YEAR、TIME、DATE、DATETIME和TIMESTAMP。
(3)字符串類型:包括CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。
1.1、整數類型
數值型數據類型主要用來存儲數字,MySQL提供了多種數值數據類型。不同的數據類型提供不同的取值範圍,可以存儲的值範圍越大,其所需要的存儲空間也就越大。MySQL主要提供的整數類型有:TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)、BIGINT。整數類型的屬性字段可以添加AUTO_INCREMENT自增約束條件。
從表中可以看到,不同類型整數存儲所需的字節數是不同的,暫用字節數最小的是TINYINT類型,佔用字節最大的是BIGINT類型,相應的佔用字節越多的類型所能表示的數值範圍越大。
根據佔用字節數可以求出每一種數據類型的取值範圍,例如TINYINT需要1個字節(8 bits)來存儲,那麼TINYINT無符號數的最大值爲2^8-1,即255;TINYINT有符號數的最大值爲2^7-1,即127。其他類型的整數的取值範圍計算方法相同。如下圖所示:
# 例如: [hellodb]> CREATE TABLE text1 (A TINYINT,B SMALLINT,C MEDIUMINT,D INT,E BIGINT); Query OK, 0 rows affected (0.42 sec) [hellodb]> DESC text1 ; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | A | tinyint(4) | YES | | NULL | | | B | smallint(6) | YES | | NULL | | | C | mediumint(9) | YES | | NULL | | | D | int(11) | YES | | NULL | | | E | bigint(20) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)
可以看到,系統將添加不同默認顯示寬度。這些顯示寬度能夠保證顯示每一種數據類型可以取到取值範圍內的所有值。例如TINYINT有符號數和無符號的數的取值範圍分別爲-128-127和0-255,由於負號佔了一個數字位,因此TINYINT默認的顯示寬度爲4,同理,其他整數類型的默認顯示寬度與其有符號數的最小值的寬度相同。
注意:顯示寬度只用於顯示,並不能限制取值範圍和佔用空間。如:INT(3)會佔用4個字節的存儲空間,並且允許的最大值也不會是999,而是INT整型所允許的最大值。
不同的整數類型有不同的取值範圍,並且需要不同的存儲空間,因此,應該根據實際需要選擇最
合適的類型,這樣有利於提高查詢的效率和節省存儲空間。整數類型是不帶小數部分的數值,現實生活中很多地方都需要用到帶小數的數值。
1.2、浮點數類型和定點數類型
MySQL中使用浮點數和定點數來表示小數。浮點類型有兩種:單精度浮點類型(FLOAT)和雙精度浮點類型(DOUBLE)。定點類型只有一種:DECIMAL。浮點類型和定點類型都可用(M,N)來表示,幾種M稱爲精度,表示總共的位數:N稱爲標度,是表示小數的位數。具體參照下圖:
DECIMAL類型不同於FLOAT和DOUBLE,DECIMAL實際是以串存放的,DECIMAL可能的最大取值範圍與DOUBLE一樣,但是其有效的取值範圍有M和D的值決定。如果改變M而固定D,則其取值範圍將隨M的變大而變大,從上面圖形可以看出,DECIMAL的存儲空間並不是固定的,而由其精度值M決定,佔用M+2個字節。
注意:不論是定點還是浮點類型,如果用戶指定的精度超出精度範圍,則會四捨五入進行處理。
# 例如: [hellodb]> CREATE TABLE text2 (A FLOAT(4,1),B DOUBLE(5,1),C DECIMAL(5,1)); Query OK, 0 rows affected (0.43 sec) MariaDB [hellodb]> DESC text2; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | A | float(4,1) | YES | | NULL | | | B | double(5,1) | YES | | NULL | | | C | decimal(5,1) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) [hellodb]> INSERT INTO text2 VALUES(5.12,5.15,5.123); Query OK, 1 row affected, 1 warning (0.06 sec) #有一個警告信息 [hellodb]> SHOW WARNINGS; #查看警告信息 +-------+------+----------------------------------------+ | Level | Code | Message | +-------+------+----------------------------------------+ | Note | 1265 | Data truncated for column 'C' at row 1 | +-------+------+----------------------------------------+ 1 row in set (0.00 sec) #可以看到FLOAT和DOUBLE在進行四捨五入時沒有給出警告,而給出C字段數值被截斷的警告; [hellodb]> SELECT * FROM text2; #查看錶信息 +------+------+------+ | A | B | C | +------+------+------+ | 5.1 | 5.2 | 5.1 | +------+------+------+ 1 row in set (0.01 sec)
# FLOAT和DOUBLE在不指定精度時,默認會按照實際的精度,DECIMAL如不指定精度默認爲(10,0)。
浮點數相對於定點數的有點是在長度一定的情況下,浮點數能夠表示更大的數據範圍:它的缺點是會引起精度問題。
在Mysql中,定點數以字符串形式存儲,在對精度要求比較高的時候(如貨幣,科學數據等)使用DECIMAL的類型比較好,另外兩個浮點數進行減法和比較運算時也容易出問題,所以在使用浮點型時需要注意,並儘量避免做浮點數比較。
1.3、日期時間類型
MySQL中有多種表示日期的數據類型,主要有:DATETIME、DATE、TIMESTAMP、TIME和YEAR。例如,當只記錄年信息的時候,可以只使用YEAR類型,而沒有必要使用DATE。每一種類型都有一個合法的取值範圍,當指定確實不合法的值時系統將“零”值插入到數據庫中。日期與時間數據類型如下:
#例如: 1、YEAR [hellodb]> CREATE TABLE text3(y YEAR); #創建表text3 Query OK, 0 rows affected (0.40 sec) [hellodb]> INSERT INTO text3 VALUES(2010),('2010'),('2166'); Query OK, 3 rows affected, 1 warning (0.22 sec) Records: 3 Duplicates: 0 Warnings: 1 #插入數據,MySQL給出了一條警告,用SHOW WARNINGS查看警告信息 [hellodb]> SHOW WARNINGS; +---------+------+--------------------------------------------+ | Level | Code | Message | +---------+------+--------------------------------------------+ | Warning | 1264 | Out of range value for column 'y' at row 3 | +---------+------+--------------------------------------------+ 1 row in set (0.00 sec) #可以看到2166超過了YEAR類型的取值範圍,但是插入進去了 [hellodb]> SELECT * FROM text3; +------+ | y | +------+ | 2010 | | 2010 | | 0000 | #插入值超過取值範圍,所以改爲0000 +------+ 3 rows in set (0.00 sec) [hellodb]> DELETE FROM text3; Query OK, 3 rows affected (0.03 sec) #清空表內容 [hellodb]> INSERT INTO text3 VALUES('O'),('00'),('77'),('10'); Query OK, 4 rows affected, 1 warning (0.03 sec) Records: 4 Duplicates: 0 Warnings: 1 #插入兩位字符串測試 [hellodb]> SELECT * FROM text3; +------+ | y | +------+ | 0000 | | 2000 | | 1977 | | 2010 | +------+ 4 rows in set (0.01 sec) 2、TIME [hellodb]> CREATE TABLE text4(t TIME); Query OK, 0 rows affected (0.19 sec) [hellodb]> INSERT INTO text4 VALUES ('10:05:05'),('23:23'),('2 10:10'),('3 02'),('10'); Query OK, 5 rows affected (0.01 sec) Records: 5 Duplicates: 0 Warnings: 0 [hellodb]> SELECT * FROM text4; +----------+ | t | +----------+ | 10:05:05 | | 23:23:00 | | 58:10:00 | | 74:00:00 | | 00:00:01 | +----------+ 5 rows in set (0.00 sec) #注:在使用'D HH'格式時,小時一定要使用雙位數值,如果是小於10的小時數,應在其前面加0。 [hellodb]> DELETE FROM text4; #清空表內容 Query OK, 5 rows affected (0.02 sec) [hellodb]> INSERT INTO text4 VALUES(CURRENT_TIME),(NOW()); Query OK, 2 rows affected, 1 warning (0.02 sec) Records: 2 Duplicates: 0 Warnings: 1 #插入當前時間 [hellodb]> SELECT * FROM text4; +----------+ | t | +----------+ | 17:41:29 | | 17:41:29 | +----------+ 2 rows in set (0.00 sec) #注:超出TIME範圍但合法的值會被轉換爲範圍最接近的端點,無效的會轉換成“00:00:00"。 3、DATE [hellodb]> CREATE TABLE text5(d DATE); Query OK, 0 rows affected (0.40 sec) [hellodb]> INSERT INTO text5 VALUES('1998-09-09'),('19980909'),('20101010'); Query OK, 3 rows affected (0.03 sec) Records: 3 Duplicates: 0 Warnings: 0 [hellodb]> SELECT * FROM text5; +------------+ | d | +------------+ | 1998-09-09 | | 1998-09-09 | | 2010-10-10 | +------------+ 3 rows in set (0.00 sec) #不同類型的日期值都正確的都可以插入到表中 [hellodb]> DELETE FROM text5; Query OK, 3 rows affected (0.02 sec) [hellodb]> INSERT INTO text5 VALUES(CURRENT_DATE()),(NOW()); Query OK, 2 rows affected, 1 warning (0.02 sec) Records: 2 Duplicates: 0 Warnings: 1 #插入當前日期 #CURRENT_DATE只返回當前日期值,不包括時間部分。 #NOW()函數返回日期和時間值,在保存到數據庫時,只保留了其日期部分。 [hellodb]> SELECT * FROM text5; +------------+ | d | +------------+ | 2016-03-07 | | 2016-03-07 | +------------+ 2 rows in set (0.01 sec)