1. 程式人生 > >CHAPTER 5 Multi-table Queries

CHAPTER 5 Multi-table Queries

多表查詢


5.1 什麼是連線

5.1.1 笛卡爾積

當查詢只連線了兩個表而未指定連線列(鍵),那麼資料庫伺服器將產生笛卡爾積,即將兩個表的所有置換。

SELECT e.fname, e.lname, d.name
FROM employee e JOIN department d;

5.1.2 內連線

要修改上一個查詢就要求我們描述清楚兩個表要如何關聯的:

SELECT e.fname, e.lname, d.name
FROM employee e JOIN department d
ON e.dept_id = d.dept_id;

若存在不匹配的e.dept_id或d.dept_id,則資料庫會將其排除,這樣的連線方式也就被稱為內連線


但是對於那些未匹配的僱員行或者部門資訊,若想包含,需要使用外連線。
 
在上述例子中,from語句並未指定所使用的連線型別,預設為內連線,實際上,最好在from子式中顯式的指定連線型別。如:

SELECT e.fname, e.lname, d.name
FROM employee e INNER JOIN department d
ON e.dept_id = d.dept_id;#由於列名相同,可以用USING(dept_id)代替。

5.1.3 ANSI連線語法

基本所有主流的資料庫管理系統都採用了SQL92的連線語法。(這就包含了一些就的連線語法)

  • 連線條件和過濾條件被分隔到兩個字句,(on子句和where子句),是查詢語句更易於理解;
  • 每兩個表之間的連線條件都在他們自己的on子句中列出,這樣不容易錯誤地忽略了某些連線條件。
  • 使用SQL92連線語法的查詢語句可以在各種資料管理系統通用。
SELECT a.account_id,a.cust_id,a.open_date,a.product_cd
FROM account a, branch b,employee e
WHERE a.open_emp_id = e.emp_id
    AND e.start_date<'2007-01-01'
    AND e.assigned_branch_id = b.branch_id
    AND (e.title =
'Teller' OR e.title ='Head Teller') AND b.name='Woburn Branch';

該查詢一方面不太容易識別where中哪些條件是連線條件,哪些是過濾條件;另一方面是對於使用了何種連線型別也並非顯而易見。(內連線還是其他)
SQL92的處理應該如下:

SELECT a.account_id,a.cust_id,a.open_date,a.product_cd
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';

這樣就顯然有連線條件都處在on語句中,過濾條件都處在where語句中。

5.2 連線3個或更多的表

參見上面,注意其中from中進行連線的表出現的次序可以任意調換,這是因為SQL是一個非過程化的語言。all you need to do is describe the object you need clearly, how to achieve it perfectly is just the databases server’s business.

5.2.1 將子查詢結果作為查詢表

SELECT a.account_id,a.cust_id,a.open_date,a.product_cd
FROM account a INNER JOIN 
    (SELECT emp_id,assigned_branch_id
    FROM employee
    WHERE start_date<'2007-01-01'
    AND (title = 'Teller' OR title ='Head Teller')) e
ON a.open_emp_id = e.emp_id
INNER JOIN
    (SELECT branch_id
    FROM branch
    WHERE b.name='Woburn Branch') b
ON e.assigned_branch_id = b.branch_id

5.2.2 連續兩次使用同一張表

若某表同時包含其他兩表的外來鍵,就需要在from子句中兩次引用該表。並最好兩次給該表不同的別名。示例如下:

SELECT a.account_id, e.emp_id, b_a.name open_branch, b_e.name emp_branch
FROM account a INNER JOIN branch b_a
    ON a.open_branch_id = b_a.branch_id
    INNER JOIN employee e
    ON a.open_emp_id = e.emp_id
    INNER JOIN branch b_e
    ON e.assigned_branch_id = b_e.branch_id
WHERE a.product_cd = 'CHK';

5.3 自連線

若一個表包含了一個紙箱自身的外來鍵,即只想本表主鍵的列,如僱員表中上級領導id指向了本表中某些職位較高的employee_id,這時候就需要我們使用自連線。

SELECT e.fname, e.lname
    e_mgr.fname mgr_lname, e_mgr.lname mgr_lname
FROM employee e INNER JOIN employee e_mgr
    ON e.superior_emp_id = e_mgr.emp_id;

5.4 相等連線和不等連線

大多數查詢使用的是相等連線,但有時也可以通過限定值的範圍實現對錶的連線,亦稱為不等連線。有時還需要使用不等自連線。
如從僱員中安排出納員們兩兩競爭:

SELECT e1.fname, e1.lname,'VS' vs,e2.fname, e2.lname
FROM employee e1 INNER JOIN employee e2
    ON e1.emp_id < e2.emp_id
WHERE e1.title = 'Teller' AND e2.title = 'Teller';

5.5 連線條件和過濾條件

最好在合適的位置放置查詢條件。