MySQL | 数据库的六种约束、表的关系、三大范式
文章目錄
- 數據庫約束
- NOT NULL(非空約束)
- UNIQUE(唯一約束)
- DEFAULT(缺省約束)
- PRIMARY KEY(主鍵約束)
- AUTO_INCREMENT 自增
- FOREIGN KEY(外鍵約束)
- CHECK(檢查約束)
- 表的設計
- 表的關系
- 一對一
- 一對多
- 多對多
- 三大范式
- 第一范式
- 第二范式
- 第三范式
數據庫約束
數據庫中主要有六種約束:
- NOT NULL(非空約束) - 指示某列不能存儲 NULL 值。
- UNIQUE(唯一約束) - 保證某列的每行必須有唯一的值。
- DEFAULT(缺省約束) - 規定沒有給列賦值時的默認值。
- PRIMARY KEY(主鍵約束) - NOT NULL 和 UNIQUE 的結合。確保某列(或兩個列多個列的結合)有唯一標識,有助于更容易更快速地找到表中的一個特定的記錄。
- FOREIGN KEY(外鍵約束) - 保證一個表中的數據匹配另一個表中的值的參照完整性。
- CHECK(檢查約束) - 保證列中的值符合指定的條件。對于 MySQL 數據庫,對 CHECK 子句進行分析,但是忽略 CHECK 子句。
NOT NULL(非空約束)
指示某列不能存儲 NULL 值。
mysql> create table book(-> id int,-> name varchar(12),-> price double,-> publish date,-> num int NOT NULL-> ); Query OK, 0 rows affected (0.02 sec)// 可以看到 num 的 NULL 屬性已經變為 NO(不允許) mysql> DESC book; +---------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | name | varchar(12) | YES | | NULL | | | price | double | YES | | NULL | | | publish | date | YES | | NULL | | | num | int | NO | | NULL | | +---------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)// 嘗試一下插入一個 num 為 NULL 的數據 mysql> INSERT INTO book VALUES(2, "C++", 13.6, "2000-08-02", NULL); ERROR 1048 (23000): Column 'num' cannot be null// 可以發現會報錯: num 列不可以為 NULLUNIQUE(唯一約束)
保證某列的每行必須有唯一的值,即對于添加了唯一約束的數據項不能有重復。
mysql> create table book(-> id int UNIQUE,-> name varchar(12),-> price double,-> publish date,-> num int-> ); Query OK, 0 rows affected (0.03 sec)// 可以看到 id 的 key 屬性已經被標記為 UNI mysql> desc book; +---------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+-------+ | id | int | YES | UNI | NULL | | | name | varchar(12) | YES | | NULL | | | price | double | YES | | NULL | | | publish | date | YES | | NULL | | | num | int | YES | | NULL | | +---------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)mysql> INSERT INTO book VALUES(1, "C++", 13.5, NULL, 10); Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO book VALUES(1, "JAVA", 3.5, "2000-08-02", 5); ERROR 1062 (23000): Duplicate entry '1' for key 'book.id' // 雖然第二條數據除了 id,其他列的值都不同于第一條數據,然而還是會報錯:重復輸入“1”作為“book.id”的值DEFAULT(缺省約束)
規定沒有給列賦值時的默認值。
mysql> create table book(-> id int,-> name varchar(12),-> price double,-> publish date DEFAULT "2000-08-02",-> num int-> ); Query OK, 0 rows affected (0.02 sec)// 可以看到 publish 的 Default 屬性被設置為 2000-08-02 mysql> desc book; +---------+-------------+------+-----+------------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+------------+-------+ | id | int | YES | | NULL | | | name | varchar(12) | YES | | NULL | | | price | double | YES | | NULL | | | publish | date | YES | | 2000-08-02 | | | num | int | YES | | NULL | | +---------+-------------+------+-----+------------+-------+ 5 rows in set (0.01 sec)// 指定列插入,不包含 publish 列 mysql> INSERT INTO book(id, name, price, num) VALUES(3, "C++", 13.5, 15); Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM book; +------+------+-------+------------+------+ | id | name | price | publish | num | +------+------+-------+------------+------+ | 3 | C++ | 13.5 | 2000-08-02 | 15 | +------+------+-------+------------+------+ 1 rows in set (0.00 sec)PRIMARY KEY(主鍵約束)
NOT NULL 和 UNIQUE 的結合。確保某列(或兩個列多個列的結合)有唯一標識,有助于更容易更快速地找到表中的一個特定的記錄。
主鍵(primary key)的特性即 非空且唯一,如果在沒有指定主鍵的時候,如果某一列(或一組列)具有非空且唯一的特性,他就會被暫定為主鍵,但是主鍵只能有一個。
表中的任何列都可以作為主鍵,只要它滿足以下條件:
- 任意兩行都不具有相同的主鍵值;
- 每個行都必須具有一個主鍵值(主鍵列不允許NULL值)。
上面提到多個列也可以作為主鍵。在使用多列作為主鍵時,上述條件必須應用到構成主鍵的所有列,所有列值的 組合 必須是唯一的(但單個列的值可以不唯一)。
除MySQL強制實施的規則外,應該堅持的幾個普遍認可的最好習慣為:
- 不更新主鍵列中的值;
- 不重用主鍵列的值;
- 不在主鍵列中使用可能會更改的值。(例如,如果使用一個名字作為主鍵以標識某個供應商,當該供應商合并和更改其名字時,必須更改這個主鍵。)
但是 非空且唯一 并不一定就是主鍵,如果有多個非空不唯一,則只有第一個是主鍵。
// 將 id 和 num 都設置為非空且唯一 mysql> CREATE TABLE pen(-> id int NOT NULL UNIQUE,-> name varchar(12),-> price double,-> num int UNIQUE NOT NULL-> ); Query OK, 0 rows affected (0.02 sec)// 只有 id 是 PRI mysql> DESC pen; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int | NO | PRI | NULL | | | name | varchar(12) | YES | | NULL | | | price | double | YES | | NULL | | | num | int | NO | UNI | NULL | | +-------+-------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)但我們之前也提到過,是允許 多個列 組成主鍵的,那么怎么實現呢?
mysql> CREATE TABLE pen(-> id int PRIMARY KEY,-> name varchar(12) PRIMARY KEY,-> price double,-> num int-> ); ERROR 1068 (42000): Multiple primary key defined通過報錯我們發現,如果在兩個列后分別聲明主鍵的話會被認為 定義了多個主鍵。
// 正確做法是在聲明完所有列之后,再聲明主鍵是由哪些列構成的 mysql> CREATE TABLE pen(-> id int,-> name varchar(12),-> price double,-> num int,-> PRIMARY KEY(id, name)-> ); Query OK, 0 rows affected (0.03 sec)mysql> DESC pen; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int | NO | PRI | NULL | | | name | varchar(12) | NO | PRI | NULL | | | price | double | YES | | NULL | | | num | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 4 rows in set (0.01 sec)AUTO_INCREMENT 自增
添加自增屬性的項必須為數字,并且必須為主鍵,并且只有缺省的時候才會使用自增。
- 如果插入的 AUTO_INCREMENT 屬性的列值為缺省,則賦值為上一條記錄的值 +1 ,沒有上一條記錄,則賦值為 1 。
- 如果刪除了表中數據,序號并不會重置,而是繼續從刪除的位置自增。
FOREIGN KEY(外鍵約束)
外鍵:外鍵為表中的某一列,包含了另一個表的主鍵,定義了兩個表之間的關系。例如學生表中存儲了班級的信息,但是在班級表中并沒有這個班級存在,就會導致數據出現沖突,所以必須將兩個表關聯起來。
語法
FOREIGN KEY (外鍵項) REFERENCES 關聯表名(關聯表中的對應項)示例
// 創建班級表 mysql> CREATE TABLE class(-> id int PRIMARY KEY AUTO_INCREMENT-> ); Query OK, 0 rows affected (0.03 sec) // 創建學生表 mysql> CREATE TABLE student(-> id int PRIMARY KEY AUTO_INCREMENT,-> num int,-> name varchar(10),-> classid int,-> FOREIGN KEY (classid) REFERENCES class(id)-> ); Query OK, 0 rows affected (0.03 sec) // 創建兩個班級 mysql> INSERT INTO class VALUES(181); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO class VALUES(182); Query OK, 1 row affected (0.00 sec) // 插入三條學生數據 mysql> INSERT INTO student(name, classid) VALUES("李四", 182); Query OK, 1 row affected (0.03 sec) mysql> INSERT INTO student(name, classid) VALUES("陳六", 181); Query OK, 1 row affected (0.00 sec) // 第三條失敗,原因在于沒有186班 mysql> INSERT INTO student(name, classid) VALUES("張三", 186); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`classid`) REFERENCES `class` (`id`))CHECK(檢查約束)
保證列中的值符合指定的條件。對于MySQL數據庫,對CHECK子句進行分析,但是忽略CHECK子句。
mysql> CREATE TABLE stu(-> id int,-> age int,-> name varchar(10),-> CHECK(id < 5)-> ); Query OK, 0 rows affected (0.03 sec)mysql> INSERT INTO stu(id) VALUES(3); Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO stu(id) VALUES(8); ERROR 3819 (HY000): Check constraint 'stu_chk_1' is violated. mysql> SELECT * FROM stu; +------+------+------+ | id | age | name | +------+------+------+ | 3 | NULL | NULL | +------+------+------+ 1 row in set (0.00 sec)值得一提的是,在 MySQL 8.0.16 版本之前的 CHECK 約束,能被解析但是被忽略掉了,就是 不符合CHECK的數據依然可以被加入到表中。 而在之后的版本上,支持 CHECK約束,但仍有缺陷!想要 INSER INTO 一個不滿足 CHECK 的數據時確實不能通過(詳見上面的示例中),但是如果 INSERT INTO 時,未設置被 CHECK 約束的 列,那么 即使這個列的默認值不符合 CHECK約束 ,也還是可以創建成功。
可以看到 主動賦值 不滿足 CHECK 的語句會報錯,而 默認值 不滿足 CHECK 的語句卻可以成功插入。
表的設計
表的關系
一對一
例如人和身份證的關系,每個人都對應有著只屬于自己的身份證:
一對多
例如學生和班級的關系,一個班級擁有多個學生,但是一個學生只能屬于一個班級:
多對多
例如學生、課程、選課表的關系。一個學生可以選擇多門課程,一個課程也可以被多個學生選擇:
三大范式
表的關系只是設計的最基礎的一項,考慮好關系,確認好數據項,將數據填進去即可。
但是那樣的設計并不合理,可能會存在 數據冗余、傳輸性能、查詢性能 等問題,所以需要用到三大范式來規范數據庫表的設計,減少數據庫的冗余性。
范式是針對數據庫表設計的幾種方案,目前關系數據庫有六種范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又稱完美范式)。
通常我們使用的都是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),所以又將他們稱為三大范式。
第一范式
要求數據庫表的每一列都是不可分割的原子數據項。
在這個表中,家庭信息和學校信息并不是原子的,例如家庭信息中包含了家庭組成和所在地,學校信息包含了年級和學位。
對于第一范式,需要確保每一項數據都是不可分割的原子性數據,不能是一個集合。因此要做出如下調整:
第二范式
在第一范式的基礎上,非主鍵數據必須完全依賴主鍵,不能部分依賴(針對組合主鍵)。
拿下面這個表來說,相同 訂單號 的 訂單時間和訂單金額 是 一樣 的,但是相同 產品號 的 訂單時間和訂單金額 卻 不一樣 。這說明訂單時間和訂單金額 部分依賴主鍵 —— 只依賴了組合主鍵中的訂單號而沒有依賴產品號 。
所以需要將其分割出去單獨建立一個表:
第三范式
在第二范式的基礎上,每一個非主鍵數據都必須要和主鍵直接依賴而非間接依賴,即不能依賴非主鍵數據。旨在體現依賴關系不可傳遞性。
如下圖,班主任性別 與 班主任年齡 直接依賴于班主任姓名(非主鍵數據),而與 主鍵——學號 并沒有直接的依賴關系,而是間接,這就是依賴傳遞:
所以需要將這兩項分割出去單獨建表:
總結
以上是生活随笔為你收集整理的MySQL | 数据库的六种约束、表的关系、三大范式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: icloud储存空间已满怎么解决(iCl
- 下一篇: linux cmake编译源码,linu