MYSQL多表查詢相關
1,普通
#查詢人員和部門所有資訊
select * from person,dept where person.did = dept.did;
#注意: 多表查詢時,一定要找到兩個表中相互關聯的欄位,並且作為條件使用
2,連線查詢
#多表連線查詢語法(重點)
SELECT 欄位列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.欄位 = 表2.欄位;
2.1, 內連線查詢 (只顯示符合條件的資料)
1 2 |
#查詢人員和部門所有資訊
select * from person inner join dept on person.did =dept.did; |
效果: 內連線查詢與多表聯合查詢的效果是一樣的
2.2, 左外連線查詢 (左邊表中的資料優先全部顯示)1 2 |
#查詢人員和部門所有資訊
select * from person left join dept on person.did =dept.did;
|
效果:人員表中的資料全部都顯示,而 部門表中的資料符合條件的才會顯示,不符合條件的會以 null 進行填充.
2.3,右外連線查詢 (右邊表中的資料優先全部顯示)
1 2 |
#查詢人員和部門所有資訊
select * from person right join dept on person.did =dept.did; |
效果:正好與[左外連線相反]
2.4全連線查詢(顯示左右表中全部資料)
全連線查詢:是在內連線的基礎上增加 左右兩邊沒有顯示的資料
注意: mysql並不支援全連線 full JOIN 關鍵字
注意: 但是mysql 提供了 UNION 關鍵字.使用 UNION 可以間接實現 full JOIN 功能
1 2 3 4 5 |
#查詢人員和部門的所有資料
SELECT * FROM person LEFT JOIN dept ON person.did = dept.did
UNION
SELECT * FROM person RIGHT JOIN dept ON person.did = dept.did; |
3,複雜條件多表查詢
3.1,查詢出 教學部 年齡大於20歲,並且工資小於40000的員工,按工資倒序排列.(要求:分別使用多表聯合查詢和內連線查詢)
#1.多表聯合查詢方式:
select * from person p1,dept d2 where p1.did = d2.did
and d2.dname='python'
and age>20
and salary <40000
ORDER BY salary DESC;
#2.內連線查詢方式:
SELECT * FROM person p1 INNER JOIN dept d2 ON p1.did= d2.did
and d2.dname='python'
and age>20
and salary <40000
ORDER BY salary DESC;
3.2,查詢每個部門中最高工資和最低工資是多少,顯示部門名稱
select MAX(salary),MIN(salary),dept.dname from
person LEFT JOIN dept
ON person.did = dept.did
GROUP BY person.did;
4,子語句查詢
4.1,
子查詢(巢狀查詢): 查多次, 多個select
注意: 第一次的查詢結果可以作為第二次的查詢的 條件 或者 表名 使用.
子查詢中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字.還可以包含比較運算子:= 、 !=、> 、<等.
1.作為表名使用
select * from (select * from person) as 表名;
ps:大家需要注意的是: 一條語句中可以有多個這樣的子查詢,在執行時,最裡層括號(sql語句) 具有優先執行權.<br>注意: as 後面的表名稱不能加引號('')
4.2,求最大工資那個人的姓名和薪水
1.求最大工資
select max(salary) from person;
2.求最大工資那個人叫什麼
select name,salary from person where salary=53000;
合併
select name,salary from person where salary=(select max(salary) from person);
4.3,求工資高於所有人員平均工資的人員
1.求平均工資
select avg(salary) from person;
2.工資大於平均工資的 人的姓名、工資
select name,salary from person where salary > 21298.625;
合併
select name,salary from person where salary >(select avg(salary) from person);
4.4,關鍵字
假設any內部的查詢語句返回的結果個數是三個,如:result1,result2,result3,那麼,
select ...from ... where a > any(...);
->
select ...from ... where a > result1 or a > result2 or a > result3;
4.5,ALL關鍵字與any關鍵字類似,只不過上面的or改成and。
即: select ...from ... where a > all(...); -> select ...from ... where a > result1 and a > result2 and a > result3;
4.6,some關鍵字和any關鍵字是一樣的功能。
所以: select ...from ... where a > some(...); -> select ...from ... where a > result1 or a > result2 or a > result3;
4.7,EXISTS 和 NOT EXISTS 子查詢語法如下:
SELECT ... FROM table WHERE EXISTS (subquery)
該語法可以理解為:主查詢(外部查詢)會根據子查詢驗證結果(TRUE 或 FALSE)來決定主查詢是否得以執行。
mysql> SELECT * FROM person
-> WHERE EXISTS
-> (SELECT * FROM dept WHERE did=5);
Empty set (0.00 sec)
此處內層迴圈並沒有查詢到滿足條件的結果,因此返回false,外層查詢不執行。
NOT EXISTS剛好與之相反
mysql> SELECT * FROM person
-> WHERE NOT EXISTS
-> (SELECT * FROM dept WHERE did=5);
+----+----------+-----+-----+--------+------+
| id | name | age | sex | salary | did |
+----+----------+-----+-----+--------+------+
| 1 | alex | 28 | 女 | 53000 | 1 |
| 2 | wupeiqi | 23 | 女 | 29000 | 1 |
| 3 | egon | 30 | 男 | 27000 | 1 |
| 4 | oldboy | 22 | 男 | 1 | 2 |
| 5 | jinxin | 33 | 女 | 28888 | 1 |
| 6 | 張無忌 | 20 | 男 | 8000 | 3 |
| 7 | 令狐沖 | 22 | 男 | 6500 | 2 |
| 8 | 東方不敗 | 23 | 女 | 18000 | NULL |
+----+----------+-----+-----+--------+------+
8 rows in set
當然,EXISTS關鍵字可以與其他的查詢條件一起使用,條件表示式與EXISTS關鍵字之間用AND或者OR來連線,如下:
mysql> SELECT * FROM person
-> WHERE AGE >23 AND NOT EXISTS
-> (SELECT * FROM dept WHERE did=5);
提示:
•EXISTS (subquery) 只返回 TRUE 或 FALSE,因此子查詢中的 SELECT * 也可以是 SELECT 1 或其他,官方說法是實際執行時會忽略 SELECT 清單,因此沒有區別。
5,其他方式查詢
5.1,臨時表查詢
需求: 查詢高於本部門平均工資的人員
解析思路: 1.先查詢本部門人員平均工資是多少.
2.再使用人員的工資與部門的平均工資進行比較
#1.先查詢部門人員的平均工資
SELECT dept_id,AVG(salary)as sal from person GROUP BY dept_id;
#2.再用人員的工資與部門的平均工資進行比較
SELECT * FROM person as p1,
(SELECT dept_id,AVG(salary)as '平均工資' from person GROUP BY dept_id) as p2
where p1.dept_id = p2.dept_id AND p1.salary >p2.`平均工資`;
ps:在當前語句中,我們可以把上一次的查詢結果當前做一張表來使用.因為p2表不是真是存在的,所以:我們稱之為 臨時表
臨時表:不侷限於自身表,任何的查詢結果集都可以認為是一個臨時表.
5.2,判斷查詢 IF關鍵字
需求1 :根據工資高低,將人員劃分為兩個級別,分別為 高階人群和低端人群。顯示效果:姓名,年齡,性別,工資,級別
select p1.*,
IF(p1.salary >10000,'高階人群','低端人群') as '級別'
from person p1;
#ps: 語法: IF(條件表示式,"結果為true",'結果為false');
5.3,需求2: 根據工資高低,統計每個部門人員收入情況,劃分為 富人,小資,平民,吊絲 四個級別, 要求統計四個級別分別有多少人
#語法一:
SELECT
CASE WHEN STATE = '1' THEN '成功'
WHEN STATE = '2' THEN '失敗'
ELSE '其他' END
FROM 表;
#語法二:
SELECT CASE age
WHEN 23 THEN '23歲'
WHEN 27 THEN '27歲'
WHEN 30 THEN '30歲'
ELSE '其他歲' END
FROM person;
SELECT dname '部門',
sum(case WHEN salary >50000 THEN 1 ELSE 0 end) as '富人',
sum(case WHEN salary between 29000 and 50000 THEN 1 ELSE 0 end) as '小資',
sum(case WHEN salary between 10000 and 29000 THEN 1 ELSE 0 end) as '平民',
sum(case WHEN salary <10000 THEN 1 ELSE 0 end) as '吊絲'
FROM person,dept where person.dept_id = dept.did GROUP BY dept_id
6,SQL邏輯查詢語句執行順序(重點)
在這些SQL語句的執行過程中,都會產生一個虛擬表,用來儲存SQL語句的執行結果(這是重點),我們現在就來跟蹤這個虛擬表的變化,得到最終的查詢結果的過程,來分析整個SQL邏輯查詢的執行順序和過程。
6.1.執行FROM語句
第一步,執行FROM
語句。我們首先需要知道最開始從哪個表開始的,這就是FROM
告訴我們的。現在有了<left_table>
和<right_table>
兩個表,我們到底從哪個表開始,還是從兩個表進行某種聯絡以後再開始呢?它們之間如何產生聯絡呢?——笛卡爾積
經過FROM語句對兩個表執行笛卡爾積,會得到一個虛擬表,暫且叫VT1(vitual table 1),內容如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 9you | shanghai | 1 | 163 |
| baidu | hangzhou | 1 | 163 |
| tx | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 2 | 163 |
| baidu | hangzhou | 2 | 163 |
| tx | hangzhou | 2 | 163 |
| 163 | hangzhou | 3 | 9you |
| 9you | shanghai | 3 | 9you |
| baidu | hangzhou | 3 | 9you |
| tx | hangzhou | 3 | 9you |
| 163 | hangzhou | 4 | 9you |
| 9you | shanghai | 4 | 9you |
| baidu | hangzhou | 4 | 9you |
| tx | hangzhou | 4 | 9you |
| 163 | hangzhou | 5 | 9you |
| 9you | shanghai | 5 | 9you |
| baidu | hangzhou | 5 | 9you |
| tx | hangzhou | 5 | 9you |
| 163 | hangzhou | 6 | tx |
| 9you | shanghai | 6 | tx |
| baidu | hangzhou | 6 | tx |
| tx | hangzhou | 6 | tx |
| 163 | hangzhou | 7 | NULL |
| 9you | shanghai | 7 | NULL |
| baidu | hangzhou | 7 | NULL |
| tx | hangzhou | 7 | NULL |
+-------------+----------+----------+-------------+
總共有28(table1的記錄條數 * table2的記錄條數)條記錄。這就是VT1的結果,接下來的操作就在VT1的基礎上進行。
6.2.執行ON過濾
執行完笛卡爾積以後,接著就進行ON a.customer_id = b.customer_id
條件過濾,根據ON
中指定的條件,去掉那些不符合條件的資料,得到VT2表,內容如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
T2就是經過ON
條件篩選以後得到的有用資料,而接下來的操作將在VT2的基礎上繼續進行。
6.3.新增外部行
這一步只有在連線型別為OUTER JOIN
時才發生,如LEFT OUTER JOIN
、RIGHT OUTER JOIN
。在大多數的時候,我們都是會省略掉OUTER
關鍵字的,但OUTER
表示的就是外部行的概念。
LEFT OUTER JOIN
把左表記為保留表,得到的結果為:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
RIGHT OUTER JOIN
把右表記為保留表,得到的結果為:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| NULL | NULL | 7 | NULL |
+-------------+----------+----------+-------------+
新增外部行的工作就是在VT2表的基礎上新增保留表中被過濾條件過濾掉的資料,非保留表中的資料被賦予NULL值,最後生成虛擬表VT3。
由於我在準備的測試SQL查詢邏輯語句中使用的是LEFT JOIN
,過濾掉了以下這條資料:
| baidu | hangzhou | NULL | NULL |
現在就把這條資料新增到VT2表中,得到的VT3表如下:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| 9you | shanghai | 3 | 9you |
| 9you | shanghai | 4 | 9you |
| 9you | shanghai | 5 | 9you |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
接下來的操作都會在該VT3表上進行。
6.4.執行WHERE過濾
對新增外部行得到的VT3進行WHERE過濾,只有符合<where_condition>的記錄才會輸出到虛擬表VT4中。當我們執行WHERE a.city = 'hangzhou'
的時候,就會得到以下內容,並存在虛擬表VT4中:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| 163 | hangzhou | 2 | 163 |
| tx | hangzhou | 6 | tx |
| baidu | hangzhou | NULL | NULL |
+-------------+----------+----------+-------------+
但是在使用WHERE子句時,需要注意以下兩點:
- 由於資料還沒有分組,因此現在還不能在WHERE過濾器中使用
where_condition=MIN(col)
這類對分組統計的過濾; - 由於還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的,如:
SELECT city as c FROM t WHERE c='shanghai';
是不允許出現的。
6.5.執行GROUP BY分組
GROU BY
子句主要是對使用WHERE
子句得到的虛擬表進行分組操作。我們執行測試語句中的GROUP BY a.customer_id
,就會得到以下內容:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163 | hangzhou | 1 | 163 |
| baidu | hangzhou | NULL | NULL |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
得到的內容會存入虛擬表VT5中,此時,我們就得到了一個VT5虛擬表,接下來的操作都會在該表上完成。
6.6.執行HAVING過濾
HAVING
子句主要和GROUP BY
子句配合使用,對分組得到的VT5虛擬表進行條件過濾。當我執行測試語句中的HAVING count(b.order_id) < 2
時,將得到以下內容:
+-------------+----------+----------+-------------+
| customer_id | city | order_id | customer_id |
+-------------+----------+----------+-------------+
| baidu | hangzhou | NULL | NULL |
| tx | hangzhou | 6 | tx |
+-------------+----------+----------+-------------+
這就是虛擬表VT6。
6.7.SELECT列表
現在才會執行到SELECT
子句,不要以為SELECT
子句被寫在第一行,就是第一個被執行的。
我們執行測試語句中的SELECT a.customer_id, COUNT(b.order_id) as total_orders
,從虛擬表VT6中選擇出我們需要的內容。我們將得到以下內容:
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| baidu | 0 |
| tx | 1 |
+-------------+--------------+
不,還沒有完,這只是虛擬表VT7。
6.8.執行DISTINCT子句
如果在查詢中指定了DISTINCT
子句,則會建立一張記憶體臨時表(如果記憶體放不下,就需要存放在硬碟了)。這張臨時表的表結構和上一步產生的虛擬表VT7是一樣的,不同的是對進行DISTINCT操作的列增加了一個唯一索引,以此來除重複資料。
由於我的測試SQL語句中並沒有使用DISTINCT,所以,在該查詢中,這一步不會生成一個虛擬表。
6.9.執行ORDER BY子句
對虛擬表中的內容按照指定的列進行排序,然後返回一個新的虛擬表,我們執行測試SQL語句中的ORDER BY total_orders DESC
,就會得到以下內容:
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| tx | 1 |
| baidu | 0 |
+-------------+--------------+
可以看到這是對total_orders列進行降序排列的。上述結果會儲存在VT8中。
6.10.執行LIMIT子句
LIMIT
子句從上一步得到的VT8虛擬表中選出從指定位置開始的指定行資料。對於沒有應用ORDER BY的LIMIT子句,得到的結果同樣是無序的,所以,很多時候,我們都會看到LIMIT子句會和ORDER BY子句一起使用。
MySQL資料庫的LIMIT支援如下形式的選擇:
LIMIT n, m
表示從第n條記錄開始選擇m條記錄。而很多開發人員喜歡使用該語句來解決分頁問題。對於小資料,使用LIMIT子句沒有任何問題,當資料量非常大的時候,使用LIMIT n, m
是非常低效的。因為LIMIT的機制是每次都是從頭開始掃描,如果需要從第60萬行開始,讀取3條資料,就需要先掃描定位到60萬行,然後再進行讀取,而掃描的過程是一個非常低效的過程。所以,對於大資料處理時,是非常有必要在應用層建立一定的快取機制(貌似現在的大資料處理,都有快取哦).
7,外來鍵約束
1.問題?
什麼是約束:約束是一種限制,它通過對錶的行或列的資料做出限制,來確保表的資料的完整性、唯一性
2.問題?
以上兩個表 person和dept中, 新人員可以沒有部門嗎?
3.問題?
新人員可以新增一個不存在的部門嗎?
4.如何解決以上問題呢?
簡單的說,就是對兩個表的關係進行一些約束(即: froegin key).
foreign key 定義:就是表與表之間的某種約定的關係,由於這種關係的存在,能夠讓表與表之間的資料,更加的完整,關連性更強。
5.具體操作
5.1建立表時,同時建立外來鍵約束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
CREATE TABLE IF NOT EXISTS dept (
did int not null auto_increment PRIMARY KEY,
dname VARCHAR(50) not null COMMENT '部門名稱'
)ENGINE=INNODB DEFAULT charset utf8;
CREATE TABLE IF NOT EXISTS person(
id int not null auto_increment PRIMARY KEY,
name VARCHAR(50) not null ,
age TINYINT(4) null DEFAULT 0,
sex enum ( '男' , '女' , '人妖' ) NOT NULL DEFAULT '人妖' ,
salary decimal (10,2) NULL DEFAULT '250.00' ,
hire_date date NOT NULL,
dept_id int (11) DEFAULT NULL,
CONSTRAINT fk_did FOREIGN KEY(dept_id) REFERENCES dept(did) -- 新增外來鍵約束
)ENGINE = INNODB DEFAULT charset utf8;
|
5.2 已經建立表後,追加外來鍵約束
1 2 3 4 5 |
#新增外來鍵約束
ALTER table person add constraint fk_did FOREIGN key(dept_id) REFERENCES dept(did);
#刪除外來鍵約束
ALTER TABLE person drop FOREIGN key fk_did;
|
定義外來鍵的條件:
(1)外來鍵對應的欄位資料型別保持一致,且被關聯的欄位(即references指定的另外一個表的欄位),必須保證唯一
(2)所有tables的儲存引擎必須是InnoDB型別.
(3)外來鍵的約束4種類型: 1.RESTRICT 2.NO ACTION 3.CASCADE 4.SET NULL
RESTRICT
同no action, 都是立即檢查外來鍵約束
NO ACTION
如果子表中有匹配的記錄,則不允許對父表對應候選鍵進行update/delete操作
CASCADE
在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄
SET NULL
在父表上update/delete記錄時,將子表上匹配記錄的列設為null (要注意子表的外來鍵列不能為not null)
(4)建議:1.如果需要外來鍵約束,最好建立表同時建立外來鍵約束.
2.如果需要設定級聯關係,刪除時最好設定為 SET NULL.
注:插入資料時,先插入主表中的資料,再插入從表中的資料。
刪除資料時,先刪除從表中的資料,再刪除主表中的資料。
8,其他約束型別
1.非空約束
關鍵字:NOT NULL ,表示 不可空. 用來約束表中的欄位列
create table t1(
id int(10) not null primary key,
name varchar(100) null
);
2.主鍵約束
用於約束表中的一行,作為這一行的識別符號,在一張表中通過主鍵就能準確定位到一行,因此主鍵十分重要。
create table t2(
id int(10) not null primary key
);
注意: 主鍵這一行的資料不能重複且不能為空。
還有一種特殊的主鍵——複合主鍵。主鍵不僅可以是表中的一列,也可以由表中的兩列或多列來共同標識
create table t3(
id int(10) not null,
name varchar(100) ,
primary key(id,name)
);
3.唯一約束
關鍵字:UNIQUE,比較簡單,它規定一張表中指定的一列的值必須不能有重複值,即這一列每個值都是唯一的。
create table t4(
id int(10) not null,
name varchar(255) ,
unique id_name(id,name)
);
//新增唯一約束
alter table t4 add unique id_name(id,name);
//刪除唯一約束
alter table t4 drop index id_name;
注意: 當INSERT語句新插入的資料和已有資料重複的時候,如果有UNIQUE約束,則INSERT失敗.
4.預設值約束
關鍵字:DEFAULT
create table t5(
id int(10) not null primary key,
name varchar(255) default '張三'
);
#插入資料
INSERT into t5(id) VALUES(1),(2);
注意: INSERT語句執行時.,如果被DEFAULT約束的位置沒有值,那麼這個位置將會被DEFAULT的值填充
9,表間關係
1.表關係分類:
總體可以分為三類: 一對一 、一對多(多對一) 、多對多
2.如何區分表與表之間是什麼關係?
#分析步驟:
#多對一 /一對多
#1.站在左表的角度去看右表(情況一)
如果左表中的一條記錄,對應右表中多條記錄.那麼他們的關係則為 一對多 關係.約束關係為:左表普通欄位, 對應右表foreign key 欄位.
注意:如果左表與右表的情況反之.則關係為 多對一 關係.約束關係為:左表foreign key 欄位, 對應右表普通欄位.
#一對一
#2.站在左表的角度去看右表(情況二)
如果左表中的一條記錄 對應 右表中的一條記錄. 則關係為 一對一關係.
約束關係為:左表foreign key欄位上 新增唯一(unique)約束, 對應右表 關聯欄位.
或者:右表foreign key欄位上 新增唯一(unique)約束, 對應右表 關聯欄位.
#多對多
#3.站在左表和右表同時去看(情況三)
如果左表中的一條記錄 對應 右表中的多條記錄,並且右表中的一條記錄同時也對應左表的多條記錄. 那麼這種關係 則 多對多 關係.
這種關係需要定義一個這兩張表的[關係表]來專門存放二者的關係
3.建立表關係
1.一對多關係
例如:一個人可以擁有多輛汽車,要求查詢某個人擁有的所有車輛。
分析:人和車輛分別單獨建表,那麼如何將兩個表關聯呢?有個巧妙的方法,在車輛的表中加個外來鍵欄位(人的編號)即可。
* (思路小結:’建兩個表,一’方不動,’多’方新增一個外來鍵欄位)*
//建立人員表
CREATE TABLE people(
id VARCHAR(12) PRIMARY KEY,
sname VARCHAR(12),
age INT,
sex CHAR(1)
);
INSERT INTO people VALUES('H001','小王',27,'1');
INSERT INTO people VALUES('H002','小明',24,'1');
INSERT INTO people VALUES('H003','張慧',28,'0');
INSERT INTO people VALUES('H004','李小燕',35,'0');
INSERT INTO people VALUES('H005','王大拿',29,'1');
INSERT INTO people VALUES('H006','周強',36,'1');
//建立車輛資訊表
CREATE TABLE car(
id VARCHAR(12) PRIMARY KEY,
mark VARCHAR(24),
price NUMERIC(6,2),
pid VARCHAR(12),
CONSTRAINT fk_people FOREIGN KEY(pid) REFERENCES people(id)
);
INSERT INTO car VALUES('C001','BMW',65.99,'H001');
INSERT INTO car VALUES('C002','BenZ',75.99,'H002');
INSERT INTO car VALUES('C003','Skoda',23.99,'H001');
INSERT INTO car VALUES('C004','Peugeot',20.99,'H003');
INSERT INTO car VALUES('C005','Porsche',295.99,'H004');
INSERT INTO car VALUES('C006','Honda',24.99,'H005');
INSERT INTO car VALUES('C007','Toyota',27.99,'H006');
INSERT INTO car VALUES('C008','Kia',18.99,'H002');
INSERT INTO car VALUES('C009','Bentley',309.99,'H005');
例子1:學生和班級之間的關係
班級表
id class_name
1 python脫產100期
2 python脫產300期
學生表 foreign key
id name class_id
1 alex 2
2 劉強東 2
3 馬雲 1
例子2: 一個女孩 擁有多個男朋友...
例子3:....
2.一對一關係
例如:一箇中國公民只能有一個身份證資訊
分析: 一對一的表關係實際上是 變異了的 一對多關係. 通過在從表的外來鍵欄位上新增唯一約束(unique)來實現一對一表關係.
#身份證資訊表
CREATE TABLE card (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
code varchar(18) DEFAULT NULL,
UNIQUE un_code (CODE) -- 建立唯一索引的目的,保證身份證號碼同樣不能出現重複
);
INSERT INTO card VALUES(null,'210123123890890678'),
(null,'210123456789012345'),
(null,'210098765432112312');
#公民表
CREATE TABLE people (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(50) DEFAULT NULL,
sex char(1) DEFAULT '0',
c_id int UNIQUE, -- 外來鍵新增唯一約束,確保一對一
CONSTRAINT fk_card_id FOREIGN KEY (c_id) REFERENCES card(id)
);
INSERT INTO people VALUES(null,'zhangsan','1',1),
(null,'lisi','0',2),
(null,'wangwu','1',3);
例子一:一個使用者只有一個部落格
使用者表:
主鍵
id name
1 egon
2 alex
3 wupeiqi
部落格表
fk+unique
id url user_id
1 xxxx 1
2 yyyy 3
3 zzz 2
例子2: 一個男人的戶口本上,一輩子最多隻能一個女主的名字.等等
3.多對多關係
例如:學生選課,一個學生可以選修多門課程,每門課程可供多個學生選擇。
分析:這種方式可以按照類似一對多方式建表,但冗餘資訊太多,好的方式是實體和關係分離並單獨建表,實體表為學生表和課程表,關係表為選修表,
其中關係表採用聯合主鍵的方式(由學生表主鍵和課程表主鍵組成)建表。
#//建立學生表
CREATE TABLE student(
id VARCHAR(10) PRIMARY KEY,
sname VARCHAR(12),
age INT,
sex CHAR(1)
);
INSERT INTO student VALUES('S0001','王軍',20,1);
INSERT INTO student VALUES('S0002','張宇',21,1);
INSERT INTO student VALUES('S0003','劉飛',22,1);
INSERT INTO student VALUES('S0004','趙燕',18,0);
INSERT INTO student VALUES('S0005','曾婷',19,0);
INSERT INTO student VALUES('S0006','周慧',21,0);
INSERT INTO student VALUES('S0007','小紅',23,0);
INSERT INTO student VALUES('S0008','楊曉',18,0);
INSERT INTO student VALUES('S0009','李傑',20,1);
INSERT INTO student VALUES('S0010','張良',22,1);
# //建立課程表
CREATE TABLE course(
id VARCHAR(10) PRIMARY KEY,
sname VARCHAR(12),
credit DOUBLE(2,1),
teacher VARCHAR(12)
);
INSERT INTO course VALUES('C001','Java',3.5,'李老師');
INSERT INTO course VALUES('C002','高等數學',5.0,'趙老師');
INSERT INTO course VALUES('C003','JavaScript',3.5,'王老師');
INSERT INTO course VALUES('C004','離散數學',3.5,'卜老師');
INSERT INTO course VALUES('C005','資料庫',3.5,'廖老師');
INSERT INTO course VALUES('C006','作業系統',3.5,'張老師');
# //建立選修表
CREATE TABLE sc(
sid VARCHAR(10),
cid VARCHAR(10),
PRIMARY KEY(sid,cid),
CONSTRAINT fk_student FOREIGN KEY(sid) REFERENCES student(id),
CONSTRAINT fk_course FOREIGN KEY(cid) REFERENCES course(id)
);
INSERT INTO sc VALUES('S0001','C001');
INSERT INTO sc VALUES('S0001','C002');
INSERT INTO sc VALUES('S0001','C003');
INSERT INTO sc VALUES('S0002','C001');
INSERT INTO sc VALUES('S0002','C004');
INSERT INTO sc VALUES('S0003','C002');
INSERT INTO sc VALUES('S0003','C005');
INSERT INTO sc VALUES('S0004','C003');
INSERT INTO sc VALUES('S0005','C001'