文章目錄
一、外鍵的介紹
- 外鍵是表的一個特殊字段。被參照的表是主表,外鍵所在字段的表爲子表。設置外鍵的原則需要記住,就是依賴於數據庫中已存在的表的主鍵。外鍵的作用是建立該表與其父表的關聯關係。父表中對記錄做操作時,子表中與之對應的信息也應有相應的改變。
- 外鍵的作用保持數據的一致性和完整性
- 可以實現一一對一或一對多的關係
- 注意
- 父表和子表必須使用相同的存儲引擎,而且禁止使用臨時表。
- 數據表的存儲引擎只能爲InnoDB。
- 外鍵列和參照列必須具有相似的數據類型。其中數字的長度或是否有符號位必須相同;而字符的長度則可以不同。
- 外鍵列和參照列必須創建索引。如果外鍵列不存在索引的話,MySQL將自動創建索引。
- 外鍵約束的參照操作
- CASCADE:從父表刪除或更新且自動刪除或更新子表中匹配的行。
- SET NULL:從父表刪除或更新行,並設置子表中的外鍵列爲NULL。如果使用該選項,必須保證子表列沒有指定NOT NULL。
- RESTRICT:拒絕對父表的刪除或更新操作。
- NO ACTION :標準SQL的關鍵字,在MySQL中與 RESTRICT相同
二、測試外鍵
1.首先嚐試內連接方式
- 創建部門表department(主表);id depName
CREATE TABLE IF NOT EXISTS department(
id TINYINT UNSIGNED AUTO_INCREMENT KEY,
depName VARCHAR(20) NOT NULL UNIQUE
)ENGINE=INNODB;
INSERT department(depName) VALUES('教學部'),
('市場部'),
('運營部'),
('督導部');
- 創建員工表employee(子表);id ,username ,depId
CREATE TABLE IF NOT EXISTS employee(
id SMALLINT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20) NOT NULL UNIQUE,
depId TINYINT UNSIGNED
)ENGINE=INNODB;
INSERT employee(username,depId) VALUES('king',1),
('queen',2),
('張三',3),
('李四',4),
('王五',1);
- 利用內連接將員工與所屬部門匹配
SELECT e.id,e.username,d.depName FROM
employee AS e
JOIN
department AS d
ON e.depId=d.id;
2.內連接的侷限性
- 刪除督導部
DELETE FROM department WHERE depName='督導部';
雖然‘督導部’現在已經沒有了,但是查詢的時候,李四仍然在4部門,也就是對應的督導部。由此,可以看出內連接方式的一致性並不是很好
mysql> SELECT * FROM employee;
+----+----------+-------+
| id | username | depId |
+----+----------+-------+
| 1 | king | 1 |
| 2 | queen | 2 |
| 3 | 張三 | 3 |
| 4 | 李四 | 4 |
| 5 | 王五 | 1 |
3.外鍵的使用
- 創建部門表department(主表);id depName
CREATE TABLE IF NOT EXISTS department(
id TINYINT UNSIGNED AUTO_INCREMENT KEY,
depName VARCHAR(20) NOT NULL UNIQUE
)ENGINE=INNODB;
INSERT department(depName) VALUES('教學部'),
('市場部'),
('運營部'),
('督導部');
(1)加入外鍵 FOREIGN KEY
- 創建員工表employee(子表);id ,username ,depId
CREATE TABLE IF NOT EXISTS employee(
id SMALLINT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20) NOT NULL UNIQUE,
depId TINYINT UNSIGNED,
FOREIGN KEY(depId) REFERENCES department(id)
)ENGINE=INNODB;
INSERT employee(username,depId) VALUES('king',1),
('queen',2),
('張三',3),
('李四',4),
('王五',1);
(2)直接刪除主表記錄失敗
- 刪除主表中的記錄
DELETE FROM department WHERE id=1;
mysql> DELETE FROM department WHERE id=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`cms`.`employee`, CONSTRAINT `employee_ibfk_1` FOREIGN KEY (`depId`) REFERENCES `department` (`id`))
(3)先對子表進行操作
- 刪除employee中的屬於1部門的人
DELETE FROM employee WHERE depId=1;
- 接下來在刪除 id=1 的部門就能成功了
DELETE FROM department WHERE id=1;
mysql> SELECT * FROM department;
+----+---------+
| id | depName |
+----+---------+
| 2 | 市場部 |
| 4 | 督導部 |
| 3 | 運營部 |
+----+---------+
(4)測試插入錯誤數據
depId=11不在範圍內,插入失敗
INSERT employee(username,depId) VALUES('test',11);
mysql> INSERT employee(username,depId) VALUES('test',11);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`cms`.`employee`, CONSTRAINT `employee_ibfk_1` FOREIGN KEY (`depId`) REFERENCES `department` (`id`))
三、外鍵的添加刪除
- 刪除員工表
DROP TABLE employee;
- 重新創建
CREATE TABLE IF NOT EXISTS cms.employee(
id SMALLINT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20) NOT NULL UNIQUE,
depId TINYINT UNSIGNED,
CONSTRAINT emp_fk_dep FOREIGN KEY(depId) REFERENCES department(id)
)ENGINE=INNODB;
INSERT employee(username,depId) VALUES('king',3),
('queen',2),
('張三',3),
('李四',4),
('王五',2);
1.刪除外鍵
ALTER TABLE employee DROP FOREIGN KEY emp_fk_dep;
2.添加外鍵
- 刪除id=2
DELETE FROM department WHERE id=2;
- 添加外鍵失敗
ALTER TABLE employee ADD CONSTRAINT emp_fk_dep FOREIGN KEY(depId) REFERENCES department(id);
提示錯誤:
mysql> ALTER TABLE employee ADD CONSTRAINT emp_fk_dep FOREIGN KEY(depId) REFERENCES department(id);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`cms`.`#sql-f18_7`, CONSTRAINT `emp_fk_dep` FOREIGN KEY (`depId`) REFERENCES `department` (`id`))
- 刪除對應的depId=2,成功
mysql> DELETE FROM employee WHERE depId=2;
ALTER TABLE employee ADD CONSTRAINT emp_fk_dep FOREIGN KEY(depId) REFERENCES department(id);
3.測試 CASCADE
- 刪除之前的表,重新創建employee和department
CREATE TABLE IF NOT EXISTS department(
id TINYINT UNSIGNED AUTO_INCREMENT KEY,
depName VARCHAR(20) NOT NULL UNIQUE
)ENGINE=INNODB;
INSERT department(depName) VALUES('教學部'),
('市場部'),
('運營部'),
('督導部');
#創建員工表employee(子表);id ,username ,depId
CREATE TABLE IF NOT EXISTS employee(
id SMALLINT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20) NOT NULL UNIQUE,
depId TINYINT UNSIGNED,
FOREIGN KEY(depId) REFERENCES department(id) ON DELETE CASCADE ON UPDATE CASCADE
#對刪除和更新操作都應用CASCADE
)ENGINE=INNODB;
INSERT employee(username,depId) VALUES('king',1),
('queen',2),
('張三',3),
('李四',4),
('王五',1);
- 刪除部門表中的第一個部門
DELETE FROM department WHERE id=1;
結果:department和employee中對應的部分和部分中的員工都被刪除了
mysql> SELECT * FROM department;
+----+---------+
| id | depName |
+----+---------+
| 2 | 市場部 |
| 4 | 督導部 |
| 3 | 運營部 |
+----+---------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM employee;
+----+----------+-------+
| id | username | depId |
+----+----------+-------+
| 2 | queen | 2 |
| 3 | 張三 | 3 |
| 4 | 李四 | 4 |
+----+----------+-------+
3 rows in set (0.00 sec)
- 更新id
UPDATE department SET id=id+10;
4.測試 SET NULL
- 刪除之前的表,重新創建employee和department
CREATE TABLE IF NOT EXISTS department(
id TINYINT UNSIGNED AUTO_INCREMENT KEY,
depName VARCHAR(20) NOT NULL UNIQUE
)ENGINE=INNODB;
INSERT department(depName) VALUES('教學部'),
('市場部'),
('運營部'),
('督導部');
CREATE TABLE IF NOT EXISTS employee(
id SMALLINT UNSIGNED AUTO_INCREMENT KEY,
username VARCHAR(20) NOT NULL UNIQUE,
depId TINYINT UNSIGNED,
FOREIGN KEY(depId) REFERENCES department(id) ON DELETE SET NULL ON UPDATE SET NULL
#刪除和更新操作都加入SET NULL
)ENGINE=INNODB;
INSERT employee(username,depId) VALUES('king',1),
('queen',2),
('張三',3),
('李四',4),
('王五',1);
- 刪除id=1
DELETE FROM department WHERE id=1;
結果:king和王五對應的depId變爲NULL
mysql> SELECT * FROM employee;
+----+----------+-------+
| id | username | depId |
+----+----------+-------+
| 1 | king | NULL |
| 2 | queen | 2 |
| 3 | 張三 | 3 |
| 4 | 李四 | 4 |
| 5 | 王五 | NULL |
+----+----------+-------+
5 rows in set (0.00 sec)
四、聯合查詢
1.簡介
- UNION
- UNION ALL
- UNION和IUNION ALL區別是UNION去掉相同記錄,UION ALL是簡單的合併到一起。
2.測試 UNION
SELECT username FROM employee UNION SELECT username FROM cms_user;
employee中有5條記錄,cms_user中有12條記錄,但是查詢結果是15條,因爲有兩條記錄重複
3.測試 UNION ALL
SELECT username FROM employee UNION ALL SELECT username FROM cms_user;
因爲UION ALL是簡單的合併到一起,所以查詢結果可以重複,共有17條
4.字段個數需匹配
- 字段個數不匹配時會報錯
SELECT id,username FROM employee UNION ALL SELECT username FROM cms_user;
報錯:
mysql> SELECT id,username FROM employee UNION ALL SELECT username FROM cms_user;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
- 只要字段個數匹配就行
SELECT id,username FROM employee UNION ALL SELECT username,age FROM cms_user;