程序員需掌握的SQL數據類型基礎(二)

1.前言

在MYSQL中每一個表的列都有其數據類型,一般的數據類型是指定數據存儲格式以及存儲長度。開發中最常見的數據類型是數值型、字符串型、日期時間類型等。

2. MYSQL數值類型

2.1 整數類型

MYSQL數值類型包括整數類型以及浮點型類型,其中整數類型有如下類型:

類型名稱 解釋說明 存儲空間
TINYINT MYSQL中最小的整數類型 1個字節
SMALLINT MYSQL中小的整數 2個字節
MEDIUMINT MYSQL中等大小整數 3個字節
INT MYSQL中默認的整數類型 4個字節
BIGINT MYSQL中最大的整數類型 8個字節

在上一篇文章中創建了tb_person的表對象,其表信息如下所示:

mysql> desc tb_person;
+---------+---------------+------+-----+---------+-------+
| Field   | Type          | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| name    | varchar(50)   | NO   |     | NULL    |       |
| address | varchar(50)   | NO   |     | NULL    |       |
| salary  | decimal(10,2) | NO   |     | NULL    |       |
| de_no   | int(11)       | YES  |     | NULL    |       |
+---------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

de_no 字段數據類型爲int(11),這表示的是該數據類型指定顯示的寬度爲11,這裏需要注意顯示寬度和實際類型存儲數據最大範圍是無關的,指定寬度是讓MYSQL最大顯示的數字長度個數,當插入的數據長度小於指定寬度時不足之處將會由空格填充。如果插入的數據大於顯示的寬度但是隻要沒有超過該數據類型最大範圍值,數值依然可以插入表中列。

顯示寬度只用於顯示,不會限制取值範圍和佔用空間,如 INT(3) 依然是佔有4個字節的空間大小且最大值也不是999。

2.2 浮點型與定點數

MYSQL中小數部分由浮點數與定點數組成。其中浮點型數值有以下類型:

類型名稱 解釋說明 存儲空間
FLOATT 單精度小數類型 4個字節
DOUBLE 雙精度小數類型 8個字節

定點數類型只有一種:

類型名稱 解釋說明 存儲空間
DEC、DECIMAL(M,D) 最大取值範圍與DOUBLE相同 M+2個字節

浮點數與定點數都可以使用(M,D)表示。其中(M,D) 意味着數值一共顯示M個數字,其中D位位於小數點後面,一般M被稱爲精度,D稱爲標度。

下面以創建一個測試表以簡單比較上述三種小數類型的區別:

mysql> create table demo1(x float(5,2),y double(5,2), z decimal(5,2))
Query OK, 0 rows affected (0.01 sec)

在x,y,z分別插入數據 5.21如下所示:

mysql> insert into demo1 values (5.21,5.21,5.21);
Query OK, 1 row affected (0.00 sec)

mysql> select * from demo1;
+------+------+------+
| x    | y    | z    |
+------+------+------+
| 5.21 | 5.21 | 5.21 |
+------+------+------+
1 row in set (0.00 sec)

可以看到數據都已經插入成功,我們再像列中同時插入數據1.315 如下所示:

mysql> insert into demo1 values (1.315,1.315,1.315);
Query OK, 1 row affected, 1 warnings (0.01 sec)

上面插入數據時候提示了警告信息我們可以查看一下警告信息如下:

mysql> show warnings;
+-------+------+----------------------------------------+
| Level | Code | Message                                |
+-------+------+----------------------------------------+
| Note  | 1265 | Data truncated for column 'z' at row 1 |
+-------+------+----------------------------------------+
1 rows in set (0.00 sec)

mysql> select * from demo1;
+------+------+------+
| x    | y    | z    |
+------+------+------+
| 5.21 | 5.21 | 5.21 |
| 1.31 | 1.31 | 1.32 |
+------+------+------+
2 rows in set (0.01 sec)

可以看到的是上述X,Y存儲數據時候進行了四捨五入沒有出現警告信息,而z字段數值直接被截斷。

我們將上述字段的精度與標度去掉然後再插入數據1.315如下所示:

mysql> alter table demo1 modify column x float;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table demo1 modify column y double;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table demo1 modify column z decimal;
Query OK, 2 rows affected, 2 warnings (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 2

mysql> desc demo1;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| x     | float         | YES  |     | NULL    |       |
| y     | double        | YES  |     | NULL    |       |
| z     | decimal(10,0) | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> select * from demo1;
+-------+-------+------+
| x     | y     | z    |
+-------+-------+------+
|  5.21 |  5.21 |    5 |
|  1.31 |  1.31 |    1 |
| 1.315 | 1.315 |    1 |
+-------+-------+------+
3 rows in set (0.00 sec)

我們發現x,y都可以進行數值的正常插入但是z字段的小數點部分已經全部被截取。

FLOAT 與 DOUBLE在不指定精度、標度時,會默認按照實際的精度進行數據插入,如果DECIMAL不指定精度則默認爲DECIMAL(10,0), 如果數值類型指定了精度與標度時,則會按照四捨五入後的結果插入表中。一般在實際開發中如賬戶餘額等對精度要求較高的情況下,一般使用的是Decimal類型且精度爲10,標度爲2

2.3 BIT類型

BIT類型可以存儲二進制數據,其默認位數位1,無法使用select關鍵字進行查詢,但是可以通過bin() 與hex()函數對數據值進行讀取。下面以一個簡單的例子演示其使用:

mysql> alter table demo1 add column w bit;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc demo1;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| x     | float         | YES  |     | NULL    |       |
| y     | double        | YES  |     | NULL    |       |
| z     | decimal(10,0) | YES  |     | NULL    |       |
| w     | bit(1)        | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> insert into demo1(w) values(1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from demo1;
+-------+-------+------+------+
| x     | y     | z    | w    |
+-------+-------+------+------+
|  5.21 |  5.21 |    5 | NULL |
|  1.31 |  1.31 |    1 | NULL |
| 1.315 | 1.315 |    1 | NULL |
|  NULL |  NULL | NULL |     |
+-------+-------+------+------+
4 rows in set (0.00 sec)

正如你上面看到的新增的一行數據w的字段位空什麼都看不到,我們在使用bin函數進行查詢:

mysql> select w, bin(w) from demo1;
+------+--------+
| w    | bin(w) |
+------+--------+
| NULL | NULL   |
| NULL | NULL   |
| NULL | NULL   |
|     | 1      |
+------+--------+
4 rows in set (0.00 sec)

3. 時間類型

MYSQL中時間類型定義的比較多,下面列出了Mysql中日期與時間類型。

類型名稱 日期格式 存儲空間
YEAR YYYY 1個字節
TIME HH:MM:SS 3個字節
DATE YYYY-MM-DD 3個字節
DATETIME YYYY-MM-DD HH:MM:SS 8個字節
TIMESTAMP YYYY-MM-DD HH:MM:SS 4個字節

DATE、DATETIME、TIMESTAMP 是MYSQL最常用的三種時間類型,下面以簡單的例子演示其使用:

mysql> create table timedemo(d date, dt datetime,ts timestamp);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into timedemo values(now(),now(),now());
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+---------------------------------------------------------------------+
| Level | Code | Message                                                             |
+-------+------+---------------------------------------------------------------------+
| Note  | 1292 | Incorrect date value: '2020-06-10 05:44:51' for column 'd' at row 1 |
+-------+------+---------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> select * from timedemo;
+------------+---------------------+---------------------+
| d          | dt                  | ts                  |
+------------+---------------------+---------------------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

在上面我們使用了now函數插入了當前的日期,其中date類型插入的數據給出了告警信息,但是數據還是能正常插入進表。我們查看錶信息如下所示:

mysql> desc timedemo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| d     | date      | YES  |     | NULL              |                             |
| dt    | datetime  | YES  |     | NULL              |                             |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
3 rows in set (0.00 sec)

可以發現系統自動位ts創建了默認值CURRENT_TIMESTAMP,並且設置了not null 和 on update CURRENT_TIMESTAMP。那麼我們像ts這個列插入null查看是否默認插入了當前系統時間如下:

mysql> insert into timedemo(ts) values(null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from timedemo;
+------------+---------------------+---------------------+
| d          | dt                  | ts                  |
+------------+---------------------+---------------------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 |
| NULL       | NULL                | 2020-06-12 22:19:38 |
+------------+---------------------+---------------------+
2 rows in set (0.01 sec)

可以很清晰看到ts的列已經插入到了數據,這裏需要注意的是Mysql只會給第一個類型爲TimeStamp設置默認值,如果有第二個類型爲TimeStamp的列將不會設置爲當前時間,我們新增一個列驗證一下:

mysql> alter table timedemo add column ts1 timestamp ;
ERROR 1067 (42000): Invalid default value for 'ts1'

我們發現增加新的TimeStamp類型必須爲其指定一個默認值,所以我們設置其默認爲null如下:

mysql> alter table timedemo add column ts1 timestamp null;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc timedemo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| d     | date      | YES  |     | NULL              |                             |
| dt    | datetime  | YES  |     | NULL              |                             |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| ts1   | timestamp | YES  |     | NULL              |                             |
+-------+-----------+------+-----+-------------------+-----------------------------+
4 rows in set (0.00 sec)

mysql> insert into timedemo(ts1) values(null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from timedemo;
+------------+---------------------+---------------------+------+
| d          | dt                  | ts                  | ts1  |
+------------+---------------------+---------------------+------+
| 2020-06-10 | 2020-06-10 05:44:51 | 2020-06-10 05:44:51 | NULL |
| NULL       | NULL                | 2020-06-12 22:19:38 | NULL |
| NULL       | NULL                | 2020-06-12 22:56:36 | NULL |
+------------+---------------------+---------------------+------+
3 rows in set (0.00 sec)

開發中經常設置的列時間類型爲datetime類型,而不是timestamp類型。其原因有如下幾點:

  1. 首先timestamp支持的範圍時間小,最大時間只能爲2038年的某一天,而datetime類型支持的時間範圍廣最大可以支持到9999年。
  2. timestamp類型的數據插入和查詢受到當前時區的影響,如果是其他時區的人看到會有時差。
  3. timestamp類型受到不同Mysql版本影響較大。

4. 字符串字符串類型

字符串類型可以存儲字符串數據,也可以存儲二進制數據。Mysql支持兩種字符類型的數據即:文本字符串和二進制字符串。其中文本字符串類型有CHARVARCHARTEXTENUMSET,下表中列出了MYSQL的文本字符串類型。

類型名稱 解釋說明 存儲空間
CHAR(M) 固定長度的文本字符串類型 可存儲0-255之間的字符長度
VARCHAR(M) 變長的文本字符串類型 M爲0-65535之間的整數,其中值長度爲M+1個字節
TINYTEXT 非常小的文本字符串類型 存儲長度在0-255個字節
TEXT 小的文本字符串類型 存儲長度爲0-65535個字節
MEDIUMTEXT 比TEXT大的文本字符串類型 存儲長度爲0-2^24個字節長度
LONGTEXT 非常大的文本字符串類型 可存儲0-2^32個字節長度
ENUM 枚舉類型 1-2個字節,取決於枚舉值數目最大65535
SET 一個字符串對象可以有0個或多個SET成員 1,2,3,4 最多支持64個成員

4.1 CHAR 與VARCHAR

CHAR(M) 與 VARCHAR(M) 兩者都可以存儲較短的字符串類型,它們唯一的區別就是:CHAR類型創建時候聲明的長度爲固定長度,當保存時候右側會填充空格以達到固定長度的值大小。而VARCHAR的實際長度爲實際存儲空間長度加一。下面將以一個例子描述兩者的區別如下所示:

  • 創建表
mysql> create table vcdemo(a char(4), b varchar(4));
Query OK, 0 rows affected (0.01 sec)
  • 插入數據
mysql> insert into vcdemo values('ab  ','ab  ');
Query OK, 1 row affected (0.00 sec)
  • 使用length函數查看列值長度
mysql> select length(a),length(b) from vcdemo;
+-----------+-----------+
| length(a) | length(b) |
+-----------+-----------+
|         2 |         4 |
+-----------+-----------+
1 row in set (0.00 sec)

從查詢結果可以看到a 在保存’ab '時候將末尾的兩個空格刪除了,而b字段保留了末尾的兩個空格。

4.2 TEXT類型

Text類型的數據可以存儲大量文本字符串,插入數據不會刪除尾部空格。一般前端文本框保存大量文本內容時候就可以使用次類型。

4.3 ENUM類型

ENUM是一個字符串類型,其值爲表創建時候在列中規定的枚舉值,其語法如下所示:

CREATE TABLE 表名 (列名 ENUM(1,2,3....));

下面一個簡單的案列演示其使用:

  • 創建表
mysql> create table enumdemo(gender enum('男','女'));
Query OK, 0 rows affected (0.01 sec)
  • 插入數據
mysql> insert into enumdemo values('男'),('女'),(null),('1');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0
  • 查詢數據
mysql> select * from enumdemo;
+--------+
| gender |
+--------+
||
||
| NULL   |
||
+--------+
4 rows in set (0.00 sec)

從上面的例子中可以看出,如果插入的數據不是枚舉類型中的值也不是null將會默認插入枚舉中的第一個值。

4.4 SET類型

SET是一個字符串對象,其與ENUM類型很相似。其語法如下所示:

CREATE TABLE 表名 (列名 SET(1,2,3....)

SET類型與ENUM類型的區別就是:SET類型可以一次選取多個成員而ENUM則最多隻能選一個。此外如果插入SET字段中的列值有重複,Mysql會自動將其去重並添加到MYSQL中。下面以一個簡單的例子演示其使用:

  • 創建表
mysql> create table setdemo( sets set('a','b','c','d'));
Query OK, 0 rows affected (0.01 sec)
  • 插入數據
mysql> insert into setdemo values('a,b'),('b,b,c'),('c,b,a');
Query OK, 3 rows affected (0.00 sec)
  • 插入數據
mysql> select * from setdemo;
+-------+
| sets  |
+-------+
| a,b   |
| b,c   |
| a,b,c |
+-------+
3 rows in set (0.00 sec)

從結果可以看到對於set類型如果插入數據重複則只取一個,於此同時插入了不按順序的值。Mysql會將其轉換爲自動順序插入,如上述’c,b,a’插入後顯示值爲’a,b,c’。

5. 二進制字符串

5.1 BINARY與VARBINARY

二進制字符串中最常見的就是BINARY,VARBINARY 其類型類似於CHAR、VARCHAR,不同的是這兩個類型存儲的是二進制字符串,其語法如下所示:

CREATE TABLE 表名 (列名 BINARY(M)| VARBINARY)

BINARY類型的長度是固定的,在指定M長度後如果存儲長度不足M長度的,則會在存儲內容後填充若干’\0’以將存儲內容達到M長度。例如爲指定列類型爲BINARY(3),當插入’a’時,存儲的內容實際爲’a\0\0’。

VARBINARY的長度是可變的,指定M長度後,其長度可以在0-M之間,例如爲指定列數據類型爲VARBINARY(3),當插入’a’時候,其存儲內容就是’a’。下面以一個簡單的案列演示其使用:

  • 創建表
mysql> create table binarydemo(a binary(3),b varbinary(3));
Query OK, 0 rows affected (0.01 sec)
  • 插入數據
mysql> insert into binarydemo values('5','5');
Query OK, 1 row affected (0.00 sec)
  • 查詢數據
mysql> select length(a),length(b) from binarydemo;
+-----------+-----------+
| length(a) | length(b) |
+-----------+-----------+
|         3 |         1 |
+-----------+-----------+
1 row in set (0.00 sec)

可以看到當插入數據不滿最大長度時候,BINARY會填充字符以達到最大長度。

5.2 BLOB類型

BLOB是一個大的二進制內容存儲類型,其存儲的是字節字符串,需注意其於TEXT的區別,TEXT存儲的是非二進制字符串內容,BLOB分爲如下幾個類型。

類型名稱 解釋說明 存儲內容
TINYBLOB 非常小的BLOB類型 存儲最大長度爲255個字節
BLOB 小的BLOB類型 存儲最大的長度爲65535個字節
MEDIUMBLOB 稍微小的BLOB類型 存儲最大長度爲2^24-1 個字節
LONGBLOB 最大的BLOB類型 最大長度爲2^ ^2-1個字節

6. JSON 類型

MYSQL從5.7.8版本後就新增了JSON類型,之前存儲JSON內容我們都是將其保存到VARCHAR或Text類型上。下面以一個簡單的例子演示此種數據類型的使用:

  • 創建表
mysql> create table jsondemo(content json);
Query OK, 0 rows affected (0.01 sec)
  • 插入數據
mysql> insert into jsondemo values('{"age":15,"gender":"男","name":"小明"}');
Query OK, 1 row affected (0.00 sec)
  • 查詢數據
mysql> select * from jsondemo;
+------------------------------------------------+
| content                                        |
+------------------------------------------------+
| {"age": 15, "name": "小明", "gender": "男"}    |
+------------------------------------------------+
1 row in set (0.00 sec)

總結

MYSQL中提供了很多的數據類型,爲了優化存儲,提高數據庫性能。需要我們清晰瞭解什麼樣的業務數據使用最精確的類型,下面將簡單總結日常開發中對於數據類型的選擇。

  1. 整數和浮點數

如果存儲的數值不包括小數部分,則使用整數類型。一般開發中常常使用的整數類型爲int,實際可以根據你的業務存儲數值大小可選擇合適的整型數值類型。

浮點數包括float和double類型,double類型比float類型高,如果對存儲浮點型數精度要求較高的情況下可選擇double類型。

  1. 浮點數和定點數

浮點數比定點數一個優勢就是浮點數能存儲更大的數,但是由於其精度都沒有定點數高,所以日常開發中對於餘額、轉賬金額等精度要求極高的數據存儲時候,decimal更能滿足我們日常業務需求而無需擔心其運算出現的精度損失的問題。

  1. 日期和時間類型

開發中最常見存儲的時間類型爲timestamp與datetime類型,timestamp存儲的時間上限爲2038年且其值插入與當前地區有關,所以日常中更多使用的是datetime類型。

  1. char 與 varchar

我們已經知道char是固定長度存儲字符串而varchar是變長的,所以char相對於varchar會佔據更多的空間,但是其處理速度比varchar速度快,這就是典型的空間換時間問題。實際開發可以根據業務選擇適合的數據類型。

  1. enum 與 set

這兩個數據類型在開發中使用頻率不是很高,enum是一個枚舉類型,如果從多個值取出一個值就可以使用枚舉。例如:性別字段適合定義枚舉類型,因爲每個人的性格只能是男、女之間的一個。set可以取多值。

  1. blob 與 text

blob是存儲二進制字符串,而text是存儲非二進制的數據,一般我們使用blob存儲圖片、音屏等信息,而text存儲文本文件。

  1. binary 與 varbinary

與char 和 varchar類似,我們知道binary是固定長度的而varbinary是變長的,當存儲內容不足的時候binary會爲存儲的數據後面加入’\0’的內容,所以其佔據更大的空間但速度更快。

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