文章目錄
- 一、第一范式(原子性)
- 二、第二范式(消除部分依賴)
- 三、第三范式(消除傳遞依賴)
- 四、表設計
- 五、聚合函數
- 六、正則表達式
MySQL 的三大范式(1NF、2NF、3NF)是關系型數據庫設計的核心原則,用于減少數據冗余、消除插入/刪除/更新異常,確保數據一致性。以下是簡明解釋:
一、第一范式(原子性)
要求:每列的值必須是不可再分的原子值。
例如:出生日期這一列存了某年某月某日,但是把出生日期這列可以拆分為年,月,日,三列,這樣的列就不具有原子性。
二、第二范式(消除部分依賴)
要求:在滿足第一范式的基礎上,非主鍵列必須完全依賴整個主鍵(不能僅依賴主鍵的一部分)。
正例:
學生表:
學號,年齡,姓名。
學生選修成績表:
學號,課程編號,成績。
在學生表中,學號作為主鍵,通過學號,可以知道年齡,通過學號也可以知道姓名。這就是完全依賴。
在學生選修成績表中,學號和課程編號作為復合主鍵,通過這個復合主鍵可以唯一確定學生的成績。
反例:
學生選修課成績表:
學號,姓名,年齡,課程名,學分,成績。
這個表中學號作為主鍵,只有姓名和年齡完全依賴于學號主鍵,學分這個字段依賴于課程名,成績字段依賴于課程名和學號這樣的復合主鍵,所以這個表只能滿足部分依賴。
三、第三范式(消除傳遞依賴)
要求:在滿足第二范式的基礎上,非主鍵列必須直接依賴主鍵,不能通過其他非主鍵列間接依賴(消除傳遞依賴)。
反例:
學生表:學號,姓名,年齡,所在院校,學院電話,學院地址。
這個表中學號作為主鍵,只有姓名和年齡和學號是強相關的。
院校電話和院校地址是和所在院校強相關的。
存在的傳遞關系:
學號->所在院校->學院電話->院校地址。
解決辦法就是將學生表一分為二。
學生表:
學號,年齡,姓名,學院編號
學院表:
學院編號,學員名,學院電話,學院地址
用學院編號作為外鍵將兩張表聯系起來。
總結:
范式 | 核心目標 | 常見問題示例 | 解決方案 |
---|---|---|---|
1NF | 列原子性 | 地址字段存復合信息 | 拆分列 |
2NF | 消除部分主鍵依賴 | 表的主鍵是組合鍵,非主鍵列依賴部分主鍵 | 拆分表 |
3NF | 消除非主鍵間的傳遞依賴 | 非主鍵列依賴其他非主鍵列 | 拆分表,建立外鍵關聯 |
四、表設計
一對一模型:
或者:
一對多:
在n端加入另一張表的主鍵。
多對多:
例如學生運動會的模型如下:
(1)有若干個班級,每個班級包括班級號、班級名、專業、人數。
(2)每個班級有若干個運動員,運動員只能屬于一個班,包括運動員號、姓名、性別、年齡。
(3)有若干個比賽項目,包括項目號、名稱、比賽地點。
(4)每個運動員可參加多個比賽項目,且每個項目可有多人參加。
(5)要求能夠公布每個比賽項目的運動員名次與成績。
(6)要求能夠公布各個班級團體總分的名次和成績。
E-R圖:
關系模型:
運動員(運動員號,班級號,姓名,性別,年齡)
班級(班級號,班級名,專業,人數)
比賽項目(項目號,比賽地點,名稱)
比賽(項目號,運動員號,成績,名次)
五、聚合函數
函數名 | 作用描述 | 是否忽略 NULL | 示例代碼(含 GROUP BY) |
---|---|---|---|
COUNT() | 統計行數或列值個數 | 是(COUNT(*)除外) | SELECT city, COUNT(*) FROM users GROUP BY city; |
SUM() | 求數值列總和 | 是 | SELECT user_id, SUM(amount) FROM orders GROUP BY user_id; |
AVG() | 求數值列平均值 | 是 | SELECT category, AVG(price) FROM products GROUP BY category; |
MAX() | 返回列最大值 | 是 | SELECT user_id, MAX(order_date) FROM orders GROUP BY user_id; |
MIN() | 返回列最小值 | 是 | `SELECT user_id, MIN(order_date) FROM |
COUNT(DISTINCT) | 統計去重后的行數 | 是 | SELECT COUNT(DISTINCT city) FROM users; |
HAVING | 對聚合結果二次過濾 | — | SELECT user_id, SUM(amount) AS total FROM orders GROUP BY user_id HAVING total>1000; |
六、正則表達式
維度 | 符號/語法 | 作用說明(一句話) | 示例片段 |
---|---|---|---|
字符集 | [a-z] | 任意單個小寫字母 | [a-z] |
[A-Z0-9] | 任意大寫字母或數字 | [A-Z0-9] | |
[^abc] | 除 a、b、c 外的任意單個字符 | [^abc] | |
[[:alnum:]] | 任意字母或數字(POSIX 類) | [[:alnum:]] | |
元字符 | . | 匹配除換行外的任意單個字符 | a.c → abc, a3c |
^ | 匹配字符串開頭 | ^abc | |
$ | 匹配字符串結尾 | xyz$ | |
\ | 轉義保留字符,使其按字面匹配 | \. 匹配真實點 | |
| | 邏輯“或” | cat|dog | |
量詞 | * | 前一項 0 次或多次 | ab*c → ac, abc |
+ | 前一項 1 次或多次 | ab+c → abc, abbc | |
? | 前一項 0 次或 1 次 | ab?c → ac, abc | |
{n} | 前一項恰好 n 次 | a{3} → aaa | |
{n,m} | 前一項 n 到 m 次 | a{2,4} → aa, aaa | |
{n,} | 前一項至少 n 次 | a{2,} → aa, aaaa |
示例1:查找 11 位手機號
SELECT * FROM users
WHERE phone REGEXP ‘^1[3-9][0-9]{9}$’;
示例二: 查找郵箱格式
SELECT * FROM users
WHERE email REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$';
示例三:查找 18 位身份證號
SELECT * FROM users
WHERE id_card REGEXP '^[0-9]{17}[0-9Xx]$';
示例四:查找包含至少 1 個大寫字母的密碼字段
SELECT * FROM users
WHERE password REGEXP '[A-Z]';
完結。