1. SQL讀書筆記——SQL中的連接(1),sql讀書筆記
《SQL學習指南》中的第5章
1.連接:
在某種機制下,需要將多個表中的數據進行整合到一起,即同一個查詢的結果集中包含來自兩個或者兩個以上的表,這種機制被稱為連接(join).
1.1 ANSI連接語法
本文采用的都是符合SQL92版本的ANSI SQL標准,所有的主流數據庫都采用了SQL92的連接語法。由於這些數據庫都出現SQL92標准發布之前,同時存在一些舊的連接語法,如下所示:
例子1:
SELECT e.fname, e.lname, d.`name`
FROM employee e , department d
WHERE e.dept_id = d.dept_id;
推薦使用SQL92標准 的連接方式,不推薦使用上面的連接方式,主要原因是:
1)連接條件和過濾條件被分隔到兩個子句中(ON子句和WHERE子句),使得查詢語句更利於理解;
2)每兩個表的連接條件都在ON子句中列出,容易找出連接條件;
3)SQL92標准可以在各種數據庫中通用,而舊的語法在不同的數據中的表現可能略有不同;
1.2 笛卡爾積
例子 1: 直接使用from連接employee 和 department表
方式一:
SELECT e.fname, e.lname, d.`name`
FROM employee e JOIN department
一個有18個雇員和3個部門,會產生54行數據,由於查詢沒有明確的指定兩個表是如何連接的造成的,這時會默認兩張表置換。這樣的連接被稱為交叉連接(cross join).
1.3 內連接
1)兩表連接
例子1: 查詢每個雇員所屬的部門信息
SELECT e.fname, e.lname, d.`name`
FROM employee e JOIN department d
ON e.dept_id = d.dept_id
結果如圖所示
此時通過描述上面兩個表是通過何種方式關聯的,是通過dept_id來關聯兩個表的。
如果在一個表中的dept_id列中存在某個值,但該值在另一張表的dept_id列中不存在,那麼此時相關的行的連接會失敗,在結果集中的相關行的連接會失敗,在結果集中將會排除包含該值的行,這種類型的連接被稱為
內連接
若想要包含某個表中的所有行,並不需要考慮該表的每一行都與另一張表匹配,那麼可以使用
外連接
2)多表內連接
-- 例子2.查詢Woburn支行中所有熟練櫃員(在2007年以前入職的櫃員)開設的賬戶
SELECT a.account_id, a.product_cd,a.open_date
FROM account a
INNER JOIN employee e
ON a.open_emp_id = e.emp_id
INNER JOIN branch b
ON e.assigned_branch_id = b.branch_id
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller')
AND b.`name` = 'Woburn Branch';
結果如圖所示:
現在FROM子句中包含3個表,兩種連接類型和兩個ON子句,看上去連接的順序是account表,employee表,然後branch表,那麼如果交換employ表和account表的連接順序會出現什麼情況呢?
SELECT a.account_id, a.product_cd,a.open_date
FROM employee e
INNER JOIN account a
ON a.open_emp_id = e.emp_id
INNER JOIN branch b
ON e.assigned_branch_id = b.branch_id
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller')
AND b.`name` = 'Woburn Branch';
結果如圖所示---無改變

那麼在更換employee和branch的順序呢?
SELECT a.account_id, a.product_cd,a.open_date
FROM branch b
INNER JOIN account a
ON a.open_branch_id = b.branch_id
INNER JOIN employee e
ON a.open_emp_id = e.emp_id
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller')
AND b.`name` = 'Woburn Branch';
結果如圖所示---無改變

那麼更換ON語句的位置呢
SELECT a.account_id, a.product_cd,a.open_date
FROM branch b
INNER JOIN account a
INNER JOIN employee e
ON a.open_branch_id = b.branch_id
ON a.open_emp_id = e.emp_id
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller')
AND b.`name` = 'Woburn Branch';
結果如圖所示---報錯!錯誤原因:ON語句連接關系要緊跟 JOIN語句

例子二多種表達方式的原因:SQL是一種非過程化的語言,也就是說只需要描述要獲取的數據對象,
而執行過程是數據庫服務器負責(我只要結果集*_*)(但是左連接,右連接的問題,還不是很確定,稍後還要進行測試一下)
3)子查詢作為結果集的內連接
例子二中的另一個版本:使用“連接 ”連接子查詢,也就是將子查詢的結果集作為查詢表進行連接
1)
SELECT e.emp_id
FROM employee e
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller');
2) SELECT b.branch_id
FROM branch b
WHERE b.`name` = 'Woburn Branch';
3) SELECT a.account_id, a.product_cd,a.open_date
FROM account a
INNER JOIN (SELECT e.emp_id
FROM employee e
WHERE e.start_date < '2007-01-01'
AND (e.title = 'Teller' OR e.title = 'Head Teller') ) em
ON a.open_emp_id = em.emp_id
INNER JOIN (SELECT b.branch_id
FROM branch b
WHERE b.`name` = 'Woburn Branch') br
ON a.open_branch_id = br.branch_id;
4)自連接
例子3.列出雇員的姓名同時列出主管的姓名:
SELECT emp.emp_id AS emp_id,CONCAT(emp.fname,' ',emp.lname) AS em,
e.emp_id AS super_em_id,CONCAT(e.fname,' ',e.lname) AS super_em
FROM employee e INNER JOIN employee emp
ON e.emp_id = emp.superior_emp_id;
結果如圖所示:

上面查詢實現了對表自身進行連接,
自連接,employee表中包含了指向自身的外鍵(superior_emp_id)
同時,employee表一共18行,但此查詢返回了17行,這是由於銀行的總經理MIchael Smith並沒
自己的主管,它的superior_emp_id列為null,因此在改行上的內連接失敗,在結果集中並不會顯示。
5)不等連接
例子4.假如執行經理決定舉辦一次面向銀行櫃員的象棋比賽,現在要創建所有對弈者的列表
SELECT CONCAT(e.fname,' ',e.lname) as TEAM_A,
'VS', CONCAT(emp.fname,' ',emp.lname) as TEAM_B
FROM employee e INNER JOIN employee emp
ON e.emp_id < emp.emp_id
WHERE e.title = 'Teller' AND emp.title = 'Teller';
結果如圖所示: