階段二模組一 MySql多表、外來鍵和資料庫設計
內容輸出來源:拉鉤教育Java就業訓練營
1 多表
實際開發中,一個專案通常需要很多張表才能完成。
1.1 單表的缺點
冗餘, 同一個欄位中出現大量的重複資料
1.2 解決方案
1.2.1 設計為兩張表
員工表中有一個欄位dept_id 與部門表中的主鍵對應,員工表的這個欄位就叫做外來鍵
擁有外來鍵的員工表 被稱為從表, 與外來鍵對應的主鍵所在的表叫做主表
1.2.2 多表設計上的問題
當我們在 員工表的 dept_id 裡面輸入不存在的部門id ,資料依然可以新增 顯然這是不合理的.
1.3 外來鍵約束
外來鍵指的是在從表中與主表的主鍵對應的那個欄位,比如員工表的 dept_id,就是外來鍵
使用外來鍵約束可以讓兩張表之間產生一個對應關係,從而保證主從表的引用的完整性
1.3.1 建立外來鍵約束
語法格式:
-- 1. 新建表時新增外來鍵
[CONSTRAINT] [外來鍵約束名稱] FOREIGN KEY(外來鍵欄位名) REFERENCES 主表名(主鍵欄位名)
-- 已有表新增外來鍵
ALTER TABLE 從表 ADD [CONSTRAINT] [外來鍵約束名稱] FOREIGN KEY (外來鍵欄位名) REFERENCES
主表(主 鍵欄位名);
1.3.2 刪除外來鍵約束
語法格式:
alter table 從表 drop foreign key 外來鍵約束名稱 -- 刪除employee 表中的外來鍵約束,外來鍵約束名 emp_dept_fk ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;
1.3.3 注意事項
-
從表外來鍵型別必須與主表主鍵型別一致 否則建立失敗.
-
新增資料時, 應該先新增主表中的資料.
-
刪除資料時,應該先刪除從表中的資料.
1.4.4 級聯刪除操作
如果想實現刪除主表資料的同時,也刪除掉從表資料,可以使用級聯刪除操作
級聯刪除 ON DELETE CASCADE -- 重新建立新增級聯操作 CREATE TABLE employee( eid INT PRIMARY KEY AUTO_INCREMENT, ename VARCHAR(20), age INT, dept_id INT, CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id) -- 新增級聯刪除 ON DELETE CASCADE );
2 多表關係
實際開發中,一個專案通常需要很多張表才能完成。
2.1 一對多關係
在從表(多方)建立一個欄位,欄位作為外來鍵指向主表(一方)的主鍵
2.2 多對多關係
需要建立第三張表,中間表中至少兩個欄位,這兩個欄位分別作為外來鍵指向各自一方的主鍵。
3 多表查詢的分類
DQL: 查詢多張表,獲取到需要的資料
3.3.1 內連線查詢
通過指定的條件去匹配兩張表中的資料, 匹配上就顯示,匹配不上就不顯示
3.3.1.1 隱式內連線
from子句 後面直接寫 多個表名 使用where指定連線條件的 這種連線方式是隱式內連線.
語法格式:
SELECT 欄位名 FROM 左表, 右表 WHERE 連線條件;
# 隱式內連線
SELECT * FROM products,category WHERE category_id = cid;
-- 可以通過給表起別名的方式, 方便我們的查詢
SELECT
p.`pname`,
p.`price`,
c.`cname`
FROM products p , category c WHERE p.`category_id` = c.`cid`;
3.3.1.1 顯式內連線
使用 inner join …on 這種方式, 就是顯式內連線
語法格式:
SELECT 欄位名 FROM 左表 [INNER] JOIN 右表 ON 條件
-- inner 可以省略
-- 查詢所有商品資訊和對應的分類資訊
# 顯式內連線查詢
SELECT * FROM products p INNER JOIN category c ON p.category_id = c.cid;
3.3.2 外連線查詢
3.3.2.1 左外連線
以左表為基準, 匹配右邊表中的資料,如果匹配的上,就展示匹配到的資料
如果匹配不到, 左表中的資料正常展示, 右邊的展示為null.
語法格式:
SELECT 欄位名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 條件
-- 左外連線查詢
SELECT * FROM category c LEFT JOIN products p ON c.`cid`= p.`category_id`;
3.3.2.2 右外連線
以右表為基準,匹配左邊表中的資料,如果能匹配到,展示匹配到的資料
如果匹配不到,右表中的資料正常展示, 左邊展示為null
語法格式:
SELECT 欄位名 FROM 左表 RIGHT [OUTER ]JOIN 右表 ON 條件
-- 右外連線查詢
SELECT * FROM products p RIGHT JOIN category c ON p.`category_id` = c.`cid`;
3.3.3 連線方式總結
內連線: inner join , 只獲取兩張表中 交集部分的資料。
左外連線: left join , 以左表為基準 ,查詢左表的所有資料, 以及與右表有交集的部分。
右外連線: right join , 以右表為基準,查詢右表的所有的資料,以及與左表有交集的部分。
4 子查詢
概念:一條select 查詢語句的結果, 作為另一條 select 語句的一部分。
特點:
子查詢必須放在小括號中
子查詢一般作為父查詢的查詢條件使用
常見分類:
where型 子查詢: 將子查詢的結果, 作為父查詢的比較條件
from型 子查詢 : 將子查詢的結果, 作為 一張表,提供給父層查詢使用
exists型 子查詢: 子查詢的結果是單列多行, 類似一個數組, 父層查詢使用 IN 函式 ,包含子查詢的結果
4.1 子查詢的結果作為查詢條件
語法格式:
SELECT 查詢欄位 FROM 表 WHERE 欄位=(子查詢);
# 通過子查詢的方式, 查詢價格最高的商品資訊
-- 1.先查詢出最高價格
SELECT MAX(price) FROM products;
-- 2.將最高價格作為條件,獲取商品資訊
SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products);
4.2 子查詢結果作為一張表
語法格式:
SELECT 查詢欄位 FROM (子查詢)表別名 WHERE 條件;
-- 查詢商品中,價格大於500的商品資訊,包括 商品名稱 商品價格 商品所屬分類名稱
-- 1. 先查詢分類表的資料
SELECT * FROM category;
-- 2.將上面的查詢語句 作為一張表使用
SELECT
p.`pname`,
p.`price`,
c.cname
FROM products p
-- 子查詢作為一張表使用時 要起別名 才能訪問表中欄位
INNER JOIN (SELECT * FROM category) c
ON p.`category_id` = c.cid WHERE p.`price` > 500;
4.3 子查詢結果是單列多行
子查詢的結果類似一個數組, 父層查詢使用 IN 函式 ,包含子查詢的結果
語法格式:
SELECT 查詢欄位 FROM 表 WHERE 欄位 IN (子查詢);
-- 查詢價格小於兩千的商品,來自於哪些分類(名稱)
-- 先查詢價格小於2000 的商品的,分類ID
SELECT DISTINCT category_id FROM products WHERE price < 2000;
-- 在根據分類的id資訊,查詢分類名稱
-- 報錯: Subquery returns more than 1 row
-- 子查詢的結果 大於一行
SELECT * FROM category
WHERE cid IN (SELECT DISTINCT category_id FROM products WHERE price < 2000);
4.4 子查詢總結
- 子查詢如果查出的是一個欄位(單列), 那就在where後面作為條件使用.
- 子查詢如果查詢出的是多個欄位(多列), 就當做一張表使用(要起別名).
5 資料庫設計
5.1 資料庫三正規化
三正規化就是設計資料庫的規則。
為了建立冗餘較小、結構合理的資料庫,設計資料庫時必須遵循一定的規則。在關係型資料庫中這種規則就稱為正規化。正規化是符合某一種設計要求的總結。要想設計一個結構合理的關係型資料庫,必須滿足一定的正規化。
滿足最低要求的正規化是第一正規化(1NF)。在第一正規化的基礎上進一步滿足更多規範要求的稱為第二正規化(2NF) , 其餘正規化以此類推。一般說來,資料庫只需滿足第三正規化(3NF)就行了
5.1.1 第一正規化 1NF
原子性, 做到列不可拆分。
第一正規化是最基本的正規化。資料庫表裡面欄位都是單一屬性的,不可再分, 如果資料表中每個欄位都是不可再分的最小資料單元,則滿足第一正規化。
5.1.2 第二正規化 2NF
在第一正規化的基礎上更進一步,目標是確保表中的每列都和主鍵相關。
一張表只能描述一件事。
5.1.3 第三正規化 3NF
消除傳遞依賴
表的資訊,如果能夠被推匯出來,就不應該單獨的設計一個欄位來存放
5.2 資料庫反三正規化
反正規化化指的是通過增加冗餘或重複的資料來提高資料庫的可讀效能
浪費儲存空間,節省查詢時間 (以空間換時間)
設計資料庫時,某一個欄位屬於一張表,但它同時出現在另一個或多個表,且完全等同於它在其本來所屬表的意義表示,那麼這個欄位就是一個冗餘欄位。
總結:
建立一個關係型資料庫設計,我們有兩種選擇
1,儘量遵循正規化理論的規約,儘可能少的冗餘欄位,讓資料庫設計看起來精緻、優雅、讓人心醉。
2,合理的加入冗餘欄位這個潤滑劑,減少join,讓資料庫執行效能更高更快。