簡介
數據庫的關聯查詢可分爲5種,它們分別是:交叉連接(CROSS JOIN)、內連接(INNER JOIN)、外連接(LEFT JOIN/RIGHT JOIN)、聯合查詢(UNION與UNION ALL)、全連接(FULL JOIN)。
實驗表A:
mysql> select * from A;
+------+--------+
| id | name |
+------+--------+
| 1 | nosee |
| 2 | chan |
| 3 | cheese |
| 4 | xyz |
+------+--------+
4 rows in set (0.00 sec)
實驗表B:
mysql> select * from B;
+------+------+
| id | age |
+------+------+
| 3 | 18 |
| 4 | 28 |
| 5 | 16 |
| 6 | 100 |
+------+------+
4 rows in set (0.00 sec)
一、交叉連接(CROSS JOIN) — 笛卡爾積
因爲沒有連接條件,所進行的表與表間的所有行的連接。,結果集會很大,沒有意義,很少使用。
語法:
SELECT * FROM A,B(,C...);
# 或者
SELECT * FROM A CROSS JOIN B (CROSS JOIN C ...);
特點:
①連接查詢沒有寫任何連接條件
②結果集中的總行數就是兩張表中總行數的乘積(笛卡爾積)
案例:
mysql> select * from A,B; # 或 select * from A CROSS JOIN B;
+------+--------+------+------+
| id | name | id | age |
+------+--------+------+------+
| 1 | nosee | 3 | 18 |
| 2 | chan | 3 | 18 |
| 3 | cheese | 3 | 18 |
| 4 | xyz | 3 | 18 |
| 1 | nosee | 4 | 28 |
| 2 | chan | 4 | 28 |
| 3 | cheese | 4 | 28 |
| 4 | xyz | 4 | 28 |
| 1 | nosee | 5 | 16 |
| 2 | chan | 5 | 16 |
| 3 | cheese | 5 | 16 |
| 4 | xyz | 5 | 16 |
| 1 | nosee | 6 | 100 |
| 2 | chan | 6 | 100 |
| 3 | cheese | 6 | 100 |
| 4 | xyz | 6 | 100 |
+------+--------+------+------+
16 rows in set (0.00 sec)
二、內連接(INNER JOIN)
多表中同時符合某種條件的數據記錄的集合。 INNER JOIN可以縮寫爲JOIN。
語法:
SELECT * FROM A,B WHERE A.id = B.id;
# 或者
SELECT * FROM A INNER JOIN B ON A.id = B.id;
還可以使用using子句做條件,但相對用的比較少。
內連接分爲3類:
1)等值連接:ON A.id = B.id
2)不等值連接:ON A.id > B.id
3)自連接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id = T2.pid;
案例:
mysql> SELECT * FROM A JOIN B ON A.id = B.id; # 或 SELECT * FROM A,B WHERE A.id = B.id;
+------+--------+------+------+
| id | name | id | age |
+------+--------+------+------+
| 3 | cheese | 3 | 18 |
| 4 | xyz | 4 | 28 |
+------+--------+------+------+
2 rows in set (0.00 sec)
三、外連接(LEFT JOIN/RIGHT JOIN)
1、左外連接
LEFT OUTER JOIN,以左表爲主,先查詢出左表,按照ON後的關聯條件匹配右表,沒有匹配到的用NULL填充,可以簡寫成LEFT JOIN。
案例:
mysql> SELECT * FROM A LEFT JOIN B ON A.id = B.id;
+------+--------+------+------+
| id | name | id | age |
+------+--------+------+------+
| 1 | nosee | NULL | NULL |
| 2 | chan | NULL | NULL |
| 3 | cheese | 3 | 18 |
| 4 | xyz | 4 | 28 |
+------+--------+------+------+
4 rows in set (0.00 sec)
2、右外連接
RIGHT OUTER JOIN,以右表爲主,先查詢出右表,按照ON後的關聯條件匹配左表,沒有匹配到的用NULL填充,可以簡寫成RIGHT JOIN。
案例:
mysql> SELECT * FROM A RIGHT JOIN B ON A.id = B.id;
+------+--------+------+------+
| id | name | id | age |
+------+--------+------+------+
| 3 | cheese | 3 | 18 |
| 4 | xyz | 4 | 28 |
| NULL | NULL | 5 | 16 |
| NULL | NULL | 6 | 100 |
+------+--------+------+------+
4 rows in set (0.01 sec)
四、聯合查詢(UNION與UNION ALL)
語法:
SELECT * FROM A UNION SELECT * FROM B UNION ...
就是把多個結果集集中在一起,UNION前的結果爲基準,需要注意的是聯合查詢的列數要相等,相同的記錄行會合並。如果使用UNION ALL,則不會合並重復的記錄行。
案例:
mysql> SELECT * FROM A UNION SELECT * FROM B;
+------+--------+
| id | name |
+------+--------+
| 1 | nosee |
| 2 | chan |
| 3 | cheese |
| 4 | xyz |
| 3 | 18 |
| 4 | 28 |
| 5 | 16 |
| 6 | 100 |
+------+--------+
8 rows in set (0.02 sec)
UNION與UNION ALL的區別:
1)對重複結果的處理:UNION會去掉重複記錄,UNION ALL不會;
2)對排序的處理:UNION會排序,UNION ALL只是簡單地將兩個結果集合並;
3)效率方面的區別:因爲UNION 會做去重和排序處理,因此效率比UNION ALL慢很多
五、全連接(FULL JOIN)
MySQL不支持全連接。
可以使用LEFT JOIN和UNION和RIGHT JOIN聯合使用來達到全連接的效果。
如:
SELECT * FROM A LEFT JOIN B ON A.id=B.id UNION
SELECT * FROM A RIGHT JOIN B ON A.id=B.id
案例:
mysql> SELECT * FROM A LEFT JOIN B ON A.id=B.id UNION
-> SELECT * FROM A RIGHT JOIN B ON A.id=B.id;
+------+--------+------+------+
| id | name | id | age |
+------+--------+------+------+
| 1 | nosee | NULL | NULL |
| 2 | chan | NULL | NULL |
| 3 | cheese | 3 | 18 |
| 4 | xyz | 4 | 28 |
| NULL | NULL | 5 | 16 |
| NULL | NULL | 6 | 100 |
+------+--------+------+------+
6 rows in set (0.00 sec)
六、嵌套查詢–子查詢
用一條SQL語句的結果作爲另一條SQL語句的條件。
如:
SELECT * FROM A WHERE id IN (SELECT id FROM B);
特點(規範):
①子查詢必須放在小括號中
②子查詢一般放在比較操作符的右邊,以增強代碼可讀性
③子查詢(小括號裏的內容)可出現在幾乎所有的SELECT子句中(如:SELECT子句、FROM子句、WHERE子句、ORDER BY子句、HAVING子句……)
注意:一個子查詢會返回一個標量(就一個值)、一個行、一個列或一個表,這些子查詢稱之爲標量、行、列和表子查詢
案例:
mysql> SELECT * FROM A WHERE id IN (SELECT id FROM B);
+------+--------+
| id | name |
+------+--------+
| 3 | cheese |
| 4 | xyz |
+------+--------+
2 rows in set (0.03 sec)
七、經典實例
1、爲了記錄足球比賽的結果,設計如下表:
1)參賽隊伍表:team
name | type | comment |
---|---|---|
teamID | int | 主鍵 |
teamName | varchar(20) | 隊伍名稱 |
mysql> select * from team;
+--------+----------+
| teamID | teamName |
+--------+----------+
| 1 | AA |
| 2 | BB |
| 3 | CC |
+--------+----------+
3 rows in set (0.00 sec)
2)賽程表:match
name | type | comment |
---|---|---|
matchID | int | 主鍵 |
hostTeanID | int | 主隊ID |
guestTeanID | int | 客隊ID |
matchResult | varchar(20) | 比賽結果 |
matchTime | date | 比賽日期 |
mysql> select * from `match`;
+---------+------------+-------------+-------------+------------+
| matchID | hostTeamID | guestTeamID | matchResult | matchTime |
+---------+------------+-------------+-------------+------------+
| 1 | 1 | 2 | 2:0 | 2006-06-05 |
| 2 | 2 | 3 | 1:2 | 2006-06-12 |
| 3 | 1 | 2 | 3:0 | 2006-06-23 |
+---------+------------+-------------+-------------+------------+
3 rows in set (0.00 sec)
要求:
其中,match賽程表中的hostTeamID與guestTeamID都和team表中的teamID關聯,查詢2006-6-1到2006-7-1之間舉行的所有比賽,並且用以下形式列出:拜仁 2:1 不菜 2006-6-22
分析:
主要的數據都在match表,基礎查詢如下:
select hostTeamID,matchResult,guestTeamID,matchTime from `match`
where matchTime between "2006-6-1" and "2006-7-1";
關聯查詢:
# 相當於3表聯合查詢。
mysql> select t1.teamName,m.matchResult,t2.teamName,m.matchTime
-> from `match` as m
-> left join team as t1 on m.hostTeamID = t1.teamID
-> left join team as t2 on m.guestTeamID = t2.teamID
-> where m.matchTime between "2006-6-1" and "2006-7-1";
+----------+-------------+----------+------------+
| teamName | matchResult | teamName | matchTime |
+----------+-------------+----------+------------+
| AA | 2:0 | BB | 2006-06-05 |
| BB | 1:2 | CC | 2006-06-12 |
| AA | 3:0 | BB | 2006-06-23 |
+----------+-------------+----------+------------+
3 rows in set (0.00 sec)