《SQL學習指南》中的第5章 1.連接: 在某種機制下,需要將多個表中的數據進行整合到一起,即同一個查詢的結果集中包含來自兩個或者兩個以上的表,這種機制被稱為連接(join). 1.1 ANSI連接語法 本文采用的都是符合SQL92版本的ANSI SQL標準,所有的主流資料庫都採用了SQL92的連接 ...
《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'; 結果如圖所示: