1. 程式人生 > >Mysql資料型別、約束、儲存引擎

Mysql資料型別、約束、儲存引擎

一、資料型別

整數型別

預設有符號的
設定為無符號
1.create table t2(age tinyint unsigned);
2.建表後用alter修改

 tinyint[(m)] [unsigned] [zerofill]

            小整數,資料型別用於儲存一些範圍的整數數值範圍:
            有符號:
                -128 ~ 127
            無符號:
                0 ~ 255

            PS: MySQL中無布林值,使用tinyint(1)構造
 int[(m)][unsigned][zerofill]

            整數,資料型別用於儲存一些範圍的整數數值範圍:
            有符號:
                    
-2147483648 ~ 2147483647 無符號: 0 ~ 4294967295
  bigint[(m)][unsigned][zerofill]
            大整數,資料型別用於儲存一些範圍的整數數值範圍:
            有符號:
                    -9223372036854775808 ~ 9223372036854775807
            無符號:
                    0  ~  18446744073709551615

注意: 

對於整數型別而言長度不是資料所佔的位元組數 是顯示資料時的寬度(字元數)
預設情況下 儲存的數值的十進位制位數 小於所設定的顯示寬度時 不會填充 沒有任何效果
加上zerofill 指定當儲存的數值的十進位制位數 小於所設定的顯示寬度時 用0來填充
當資料的十進位制位長度 大於顯示寬度 可以正常顯示
記住 整型後面的長度的含義
tinyint            1位元組
smallint         2 位元組
mediumint     3位元組
int                4位元組


bigint            8位元組
總結:除了儲存範圍沒啥區別,都是整型,預設有符號,對於顯示寬度 原理是相同的,長度引數如果不指定 會有預設值

# 建立表一個是預設寬度的int,一個是指定寬度的int(5)
mysql> create table t1 (id1 int,id2 int(5));
Query OK, 0 rows affected (0.02 sec)

# 像t1中插入資料1,1
mysql> insert into t1 values (1,1);
Query OK, 1 row affected (0.01 sec)

# 可以看出結果上並沒有異常
mysql> select * from t1;
+------+------+
| id1  | id2  |
+------+------+
|    1 |    1 |
+------+------+
row in set (0.00 sec)

# 那麼當我們插入了比寬度更大的值,會不會發生報錯呢?
mysql> insert into t1 values (111111,111111);
Query OK, 1 row affected (0.00 sec)

# 答案是否定的,id2仍然顯示了正確的數值,沒有受到寬度限制的影響
mysql> select * from t1;
+------------+--------+
| id1        | id2    |
+------------+--------+
| 0000000001 |  00001 |
| 0000111111 | 111111 |
+------------+--------+
rows in set (0.00 sec)

# 修改id1欄位 給欄位新增一個unsigned表示無符號
mysql> alter table t1 modify id1 int unsigned;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc t1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id1   | int(10) unsigned | YES  |     | NULL    |       |
| id2   | int(5)           | YES  |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
rows in set (0.01 sec)

# 當給id1新增的資料大於214748364時,可以順利插入
mysql> insert into t1 values (2147483648,2147483647);
Query OK, 1 row affected (0.00 sec)

# 當給id2新增的資料大於214748364時,會報錯
mysql> insert into t1 values (2147483647,2147483648);
ERROR 1264 (22003): Out of range value for column 'id2' at row 1

int整數示例
整數示例

 

浮點型別

float            4位元組
double         8位元組
decimal       不固定
create table t9(num float(m,d))
m 表示總長度 d 表示小數部分的長度,長度表示不是資料儲存範圍 而是字元長度
10.12 總長為4 小數部分為2

各個型別的最大長度
float     (255,30) 
double  (255,30)
decimal (65,30)

區別:
float與double的精度不同 都是不準確的小數
decimal 準確的小數 不會丟失精度

具體使用哪種型別得根據使用場景判斷
float滿足大部分使用場景
decimal適合銀行系統 科學研究等

括號中m和d的值 可以限制資料儲存範圍 與整型不同
重點:記住m和d的含義 

# 建立表的三個欄位分別為float,double和decimal引數表示一共顯示5位,小數部分佔2位
mysql> create table t2 (id1 float(5,2),id2 double(5,2),id3 decimal(5,2));
Query OK, 0 rows affected (0.02 sec)

# 向表中插入1.23,結果正常
mysql> insert into t2 values (1.23,1.23,1.23);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
+------+------+------+
row in set (0.00 sec)

# 向表中插入1.234,會發現4都被截斷了
mysql> insert into t2 values (1.234,1.234,1.234);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
| 1.23 | 1.23 | 1.23 |
+------+------+------+
rows in set (0.00 sec)

# 向表中插入1.235發現數據雖然被截斷,但是遵循了四捨五入的規則
mysql> insert into t2 values (1.235,1.235,1.235);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
| 1.23 | 1.23 | 1.23 |
| 1.24 | 1.24 | 1.24 |
+------+------+------+
rows in set (0.00 sec)

# 建新表去掉引數約束
mysql> create table t3 (id1 float,id2 double,id3 decimal);
Query OK, 0 rows affected (0.02 sec)

# 分別插入1.234
mysql> insert into t3 values (1.234,1.234,1.234);
Query OK, 1 row affected, 1 warning (0.00 sec)

# 發現decimal預設值是(10,0)的整數
mysql> select * from t3;
+-------+-------+------+
| id1   | id2   | id3  |
+-------+-------+------+
| 1.234 | 1.234 |    1 |
+-------+-------+------+
row in set (0.00 sec)

# 當對小數位沒有約束的時候,輸入超長的小數,會發現float和double的區別
mysql> insert into t3 values (1.2355555555555555555,1.2355555555555555555,1.2355555555555555555555);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from t3;
+---------+--------------------+------+
| id1     | id2                | id3  |
+---------+--------------------+------+
|   1.234 |              1.234 |    1 |
| 1.23556 | 1.2355555555555555 |    1 |
+---------+--------------------+------+
rows in set (0.00 sec)
小數示例

 

字串型別

常用兩種
char 定長字串
varchar 可變長度字串
注意字串中 長度指定的是資料的字元長度 與位元組沒關係

create table t13(c1 char,c2 varchar(10));
在建立時 varchar必須指定長度 char有預設值

不同點:
a char(3)  b char(3)
A |B |
char型別在取資料時 就根據長度來獲取 不關心真實資料長度
無論的資料有多長 佔用的空間是固定的 造成了一定空間浪費

a varchar(30)  b varchar(30)
(1)A(1)B
varchar型別在取資料時 先獲取資料長度 在根據長度獲取真實資料 關心真實資料長度
先儲存長度需要一個位元組 再儲存真實資料 不會浪費空間
但是 由於需要計算資料的長度 所以存取速度會比定長慢

相同點:
括號中的數字 都是表示儲存最大字元長度

char使用頻率更高

mysql> create table t9 (v varchar(4),c char(4));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t9 values ('ab  ','ab  ');
Query OK, 1 row affected (0.00 sec)

# 在檢索的時候char資料型別會去掉空格
mysql> select * from t9;
+------+------+
| v    | c    |
+------+------+
| ab   | ab   |
+------+------+
row in set (0.00 sec)

# 來看看對查詢結果計算的長度
mysql> select length(v),length(c) from t9;
+-----------+-----------+
| length(v) | length(c) |
+-----------+-----------+
|         4 |         2 |
+-----------+-----------+
row in set (0.00 sec)

# 給結果拼上一個加號會更清楚
mysql> select concat(v,'+'),concat(c,'+') from t9;
+---------------+---------------+
| concat(v,'+') | concat(c,'+') |
+---------------+---------------+
| ab  +         | ab+           |
+---------------+---------------+
row in set (0.00 sec)

# 當儲存的長度超出定義的長度,會截斷
mysql> insert into t9 values ('abcd  ','abcd  ');
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> select * from t9;
+------+------+
| v    | c    |
+------+------+
| ab   | ab   |
| abcd | abcd |
+------+------+
rows in set (0.00 sec)
char/varchar示例

mysql會在儲存資料時自動將資料末尾的空格去掉
如果必須要存空格 需要修改sql_mode 增加 PAD_CHAR_TO_FULL_LENGTH 意思是把空格當作有效資料


由於自動去除空格這個機制 在使用等於符號 和like時有區別
select *from t1 where name = "yh "; 會自動去除空格
select *from t1 where name like "yh "; 不會自動去除空格
like 用於模糊匹配 使用%表示0或任意個任意字元 使用_表示一個任意字元

日期和時間
year
time
date
datetime  
timestamp  
timestamp特點是:可以給null 自動輸入當前時間 當這條記錄被修改了會自動更新當前時間

mysql> create table t4 (d date,t time,dt datetime);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t4;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| d     | date     | YES  |     | NULL    |       |
| t     | time     | YES  |     | NULL    |       |
| dt    | datetime | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
rows in set (0.01 sec)

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

mysql> select * from t4;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 |
+------------+----------+---------------------+
row in set (0.00 sec)

mysql> insert into t4 values (null,null,null);
Query OK, 1 row affected (0.01 sec)

mysql> select * from t4;
+------------+----------+---------------------+
| d          | t        | dt                  |
+------------+----------+---------------------+
| 2018-09-21 | 14:51:51 | 2018-09-21 14:51:51 |
| NULL       | NULL     | NULL                |
+------------+----------+---------------------+
rows in set (0.00 sec)
date/time/datetime示例
mysql> create table t5 (id1 timestamp);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t5;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id1   | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
row in set (0.00 sec)

# 插入資料null,會自動插入當前時間的時間
mysql> insert into t5 values (null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t5;
+---------------------+
| id1                 |
+---------------------+
| 2018-09-21 14:56:50 |
+---------------------+
row in set (0.00 sec)

#新增一列 預設值是'0000-00-00 00:00:00'
mysql> alter table t5 add id2 timestamp;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table t5 \G;
*************************** 1. row ***************************
       Table: t5
Create Table: CREATE TABLE `t5` (
  `id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
row in set (0.00 sec)

ERROR: 
No query specified

# 手動修改新的列預設值為當前時間
mysql> alter table t5 modify id2 timestamp default current_timestamp;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table t5 \G;
*************************** 1. row ***************************
       Table: t5
Create Table: CREATE TABLE `t5` (
  `id1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id2` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8
row in set (0.00 sec)

ERROR: 
No query specified

mysql> insert into t5 values (null,null);
Query OK, 1 row affected (0.01 sec)

mysql> select * from t5;
+---------------------+---------------------+
| id1                 | id2                 |
+---------------------+---------------------+
| 2018-09-21 14:56:50 | 0000-00-00 00:00:00 |
| 2018-09-21 14:59:31 | 2018-09-21 14:59:31 |
+---------------------+---------------------+
rows in set (0.00 sec)
timestamp示例
mysql> create table t6 (t1 timestamp);
Query OK, 0 rows affected (0.02 sec)

mysql> desc t6;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| t1    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
row in set (0.01 sec)

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

mysql> select * from t6;
+---------------------+
| t1                  |
+---------------------+
| 1970-01-01 08:00:01 |
+---------------------+
row in set (0.00 sec)
# timestamp時間的下限是19700101080001
mysql> insert into t6 values (19700101080000);
ERROR 1292 (22007): Incorrect datetime value: '19700101080000' for column 't1' at row 1

mysql> insert into t6 values ('2038-01-19 11:14:07');
Query OK, 1 row affected (0.00 sec)
# timestamp時間的上限是2038-01-19 11:14:07
mysql> insert into t6 values ('2038-01-19 11:14:08');
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 11:14:08' for column 't1' at row 1
mysql> 
timestamp示例2
mysql> create table t7 (y year);
Query OK, 0 rows affected (0.02 sec)

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

mysql> select * from t7;
+------+
| y    |
+------+
| 2018 |
+------+
row in set (0.00 sec)
year示例
mysql> create table t8 (dt datetime);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t8 values ('2018-9-26 12:20:10');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t8 values ('2018/9/26 12+20+10');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t8 values ('20180926122010');
Query OK, 1 row affected (0.00 sec)

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

mysql> select * from t8;
+---------------------+
| dt                  |
+---------------------+
| 2018-09-26 12:20:10 |
| 2018-09-26 12:20:10 |
| 2018-09-26 12:20:10 |
| 2018-09-26 12:20:10 |
+---------------------+
rows in set (0.00 sec)
datetime示例

列舉
enum 可以指定一堆字串的值 在插入資料時 資料必須這堆字串中的其中一個 ("男的","女的") 多選一


集合
set 可以指定一堆字串的值 在插入資料時 資料必須這堆字串中的其中一個或多個 ("男的","女的") 多選多

共同點:資料都是字串型別

mysql> create table t10 (name char(20),gender enum('female','male'));
Query OK, 0 rows affected (0.01 sec)

# 選擇enum('female','male')中的一項作為gender的值,可以正常插入
mysql> insert into t10 values ('nezha','male');
Query OK, 1 row affected (0.00 sec)

# 不能同時插入'male,female'兩個值,也不能插入不屬於'male,female'的值
mysql> insert into t10 values ('nezha','male,female');
ERROR 1265 (01000): Data truncated for column 'gender' at row 1

mysql> create table t11 (name char(20),hobby set('抽菸','喝酒','燙頭','翻車'));
Query OK, 0 rows affected (0.01 sec)

# 可以任意選擇set('抽菸','喝酒','燙頭','翻車')中的項,並自帶去重功能
mysql> insert into t11 values ('yuan','燙頭,喝酒,燙頭');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t11;
+------+---------------+
| name | hobby        |
+------+---------------+
| yuan | 喝酒,燙頭     |
+------+---------------+
row in set (0.00 sec)

# 不能選擇不屬於set('抽菸','喝酒','燙頭','翻車')中的項,
mysql> insert into t11 values ('alex','燙頭,翻車,看妹子');
ERROR 1265 (01000): Data truncated for column 'hobby' at row 1
set/enum示例

二、約束

是一種對資料限制,資料型別 unsigned無符號 字串長度 浮點的長度。

約束的作用是?
為了保證資料的正確性,完整性
例如要儲存密碼 char(20) 只限制了型別和長度, 無法保證資料的正確性

額外的約束
語法:
建立時指定約束
create table 表名稱(欄位名 型別(長度) 約束名稱1 約束名稱n,....)
後期修改的方式新增 約束
alter table 表名稱 modify 欄位名 型別(長度) 約束名稱1 約束名稱n,....

    NOT NULL 非空約束  限制該欄位的值不能為空
    UNIQUE 唯一性約束  限制該欄位的值是唯一的不能出現重複
    DEFAULT 預設值約束 如果插入資料時沒有指定該欄位的值則使用預設值
    PRIMARY KEY 主鍵約束 限制該欄位 不能為空 並且是唯一的   可以唯一標識一條資料 *****
    FOREIGN KEY 外來鍵約束 用來指向另一個表的主鍵

每一個表都應該有一個主鍵 需要唯一標識 否則可以可能出現完全相同的兩個資料 無法區分
UNIQUE 不能重複 但是可以為空 這樣也不能唯一標識
UNIQUE NOT NULL 不能為空且唯一 可以唯一標識一條資料 書寫順序無所謂

UNIQUE NOT NULL 與 主鍵的區別:

UNIQUE NOT NULL 不能被其他表引用 (不能作為其它表的外來鍵)
UNIQUE NOT NULL 約束一個表中可以有多個 但是主鍵只能有一個

三、索引

索引:用於加速查詢
InnoDB 中 索引是樹形結構,為了提高查詢效率 InnoDB為找一個不為空 且唯一的欄位作為主鍵
如果表中不存在這樣的欄位 會自動幫你建一個隱藏主鍵欄位 但是無法提升查詢效率

只要是使用innoDB 就應該為每個表指定一個非空 且唯一的欄位

InnoDB阻止資料時 首先使用主鍵 如果沒有主鍵 找一個非空且唯一 如果也沒有 建一個隱藏欄位

多欄位聯合主鍵: 不常用
學生表 stu_id course_id 做為聯合主鍵
1 1 已有資料
1 2 可以插入
2 1 可以插入
1 1 不能插入
只有當兩個欄位都重複才算重複

當一個表中 由於業務需求沒有一個非空且唯一的欄位時 我們可以建一個新的欄位專門作為主鍵
管理主鍵的值挺麻煩的 你得記錄上一次的主鍵值
mysql可以幫你自動管理主鍵 auto_increment 自動增長
auto_increment 只能用於整型欄位 並且該欄位必須具備索引
所以 通常 主鍵都會加上auto_increment

手動修改自動增長計數
alter table 表名 auto_increment 新的值;
注意:如果新的值小於當前的最大值 是無效的

通常建一個表就要建一個主鍵 主鍵的型別通常是整型

四、儲存引擎

儲存引擎
        發動機
        汽油機
        柴油機 柴油價格便宜 動力還強  噪音大  不完全燃燒
        電機 加速快  噪音小  續航問題

一個產品或服務的核心部分稱之為引擎
        mysql的核心功能存取資料
        mysql儲存引擎就是負責存取資料那一段程式碼
儲存引擎
   InnoDB
        為何預設 支援事務  行級鎖 外來鍵
    BLACKHOLE
        寫進去就沒了
    MEMORY
        存到記憶體中 斷電易失
    MYISAM
        不支援支援事務  行級鎖 外來鍵
        支援儲存結構體 例如point x座標 y座標  支援空間索引
引擎種類

五、嚴格模式

什麼是嚴格模式  對插入的資料嚴格要求 不再範圍內直接報錯  例如往tinyint中插入大於255的值將報錯
    什麼是非嚴格模式 不 對插入的資料嚴格要求 不再範圍內也可以儲存 儲存的當前型別最大支援的值
    5.6預設是非嚴格模式
    5.7以後預設嚴格模式

    檢視SQL模式
        select @@sql_mode;
        show variables like "sql_mode";

    修改SQL模式
        set @@sql_mode = "";
    正常情況不需要改
嚴格模式