1. 程式人生 > 資訊 >西十高鐵湖北段正式開工:建成後武漢到西安只需 2 小時

西十高鐵湖北段正式開工:建成後武漢到西安只需 2 小時

12.18

1.多表查詢

#查詢員工名為'Abel'的人在哪裡工作
SELECT *
FROM employees
WHERE last_name ='Abel';
#得到結果department_id為80
#在departments表中查詢department_id為80的工作地點
SELECT *
FROM departments
WHERE department_id=80;
#得到結果location_id為2500
#在locations表中查詢location_id為2500
SELECT *
FROM locations
WHERE location_id=2500;
#得到city為Oxford
#綜上員工名為'Abel'的人在Oxford工作
#進行了三次查詢!
  • Q:可以將多張表寫在一張表上嗎?為什不那麼做?

  • A:可以!防止資料的冗餘。用上述例子來舉例,一個員工有一個部門號department_id,部門表中有部門名字,那麼如果寫在一張表中,相同部門號的員工就會有大段文字重複。或者有的員工沒有部門,則會有null值的存在,又或者有些部門還有員工,則前方會有null值。

    last_name department_id department_name
    zhangsan 1000 Finance
    lisi 1000 Finance
    wangwu null null
    null 1001 Corporate Tax

1.1 多表查詢SQL92

#查詢員工的姓名及其部分名稱
SELECT employee_id,department_id
FROM employees,departments
#如上是錯誤的!每一個employee_id對應了每一個department_id,107*27=2889條資料
#上述錯誤被稱為笛卡爾積的錯誤。
#查詢員工的姓名及其部分名稱
SELECT employee_id,department_name
FROM employees,departments
WHERE employees.department_id=departments.department_id;
#過濾條件為employees表中department_id與departments表中department_id相等
1.1.1怎樣會出現笛卡爾積的錯誤
  • 省略多表的查詢條件(或關聯條件)

  • 連線條件(或關聯條件)無效

  • 所有表中所有行的互相連線


1.1.2 Ambiguous問題

對錶中共有的欄位進行查詢時,必須指明該欄位出自哪一個表

從SQL優化的角度,建議在每個欄位前都指明其出自的表!

SELECT employee_id,department_name,department_id
FROM employees,departments
WHERE employees.department_id=departments.department_id;
#如上是錯誤的,Column 'department_id' in field list is ambiguous
#department_id在是不明確的
SELECT employees.employee_id,departments.department_name,departments.department_id
FROM employees,departments
WHERE employees.department_id=departments.department_id;

1.1.3 表的別名
  1. 由於要給每個欄位加上欄位的出處,使得SQL語句複雜化,因此建議在SQL語句中給表加上別名
  2. WHERE中不能使用列的別名,但是可以使用表的別名
  3. 一旦使用表的別名,在WHERE和SELECT則必須使用別名
SELECT t1.employee_id,t2.department_name,t2.department_id
FROM employees t1,departments t2
WHERE t1.department_id=t2.department_id;

1.2結論

結論:如果有n個表實現多表查詢,則至少要有n-1個條件 。


1.3多表查詢的分類

1.3.1等值連線和非等值連結
  • 如名字就可以知道意思
SELECT employee_id,salary,grade_level
FROM employees e,job_grades j
WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;
#根據employees表中salary的數值比較job_grades表中的區間來得到job_grades表中的grade_level然後輸出
1.3.2自連線和非自連線
  • 自己連結自己就是自連線,多個表中的連線就是非自連線。
#練習:查詢員工id,員工姓名,及其管理者的id和姓名
SELECT emp.employee_id,emp.last_name,man.employee_id,man.last_name
FROM employees emp,employees man
WHERE emp.manager_id=man.employee_id;
#完成自連線
1.3.3自連線和外連線
  • 合併具有同一列的兩個以上的表的行,結果集中不包含一個表與另一個表不匹配的行,則稱為內連線

  • 如上所寫的內容都是內連線

  • 合併具有同一列的兩個以上的表的行,結果集中除了包含一個表與另一個表匹配的行之外,還查詢到了左表或右表中不匹配的行,則稱為外連線。

SELECT emp.employee_id,emp.last_name,man.employee_id,man.last_name
FROM employees emp,employees man
WHERE emp.manager_id=man.employee_id+;
#在MYSQL中不認可SQL92的外連線寫法,即上述寫法會報錯!但是Oracle可以。

在此之前需要先學習SQL99中的多表查詢。

1.4多表查詢SQL99

1.4.1內連線
  • 語法其實很簡單,將上述描述FROM中的“,”改為JOIN;將WHERE改為ON。
  • JOIN+表名+ON+連線條件!
  • 其實內連線用的是INNER JOIN,INNER可以省略!
SELECT t1.employee_id,t2.department_name,t2.department_id
FROM employees t1 JOIN departments t2
ON t1.department_id=t2.department_id;
  • 多個條件時,則寫多個JOIN...ON
SELECT last_name,department_name,city
FROM employees e JOIN departments d
ON e.department_id =d.department_id
JOIN locations l
ON d.location_id=l.location_id
1.4.2 外連線
  • 將INNER JOIN改為OUTER JOIN
  • 左外連線為LEFT OUTER JOIN
  • 右外連線為RIGHT OUTER JOIN
  • 其中有LEFT或者RIGHT使,OUTER可以省略
#查詢所有員工的last_name,department_name資訊
SELECT last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id; 
1.4.3全外連線
  • MySQL不支援FULL OUTER JOIN。
1.4.4UNION和UNION ALL
  • UNION和UNION ALL是將兩個結果集合併為一個

  • UNION會對返回的結果集進行去重

  • 如果明確知道返回的結果不存在重複資料或者不需要去重的,則儘量使用UNION ALL語句,以提高資料效率

假設A為員工表,B為部門表

  • 中圖——內連線

    SELECT employee_id,department_name
    FROM employees e JOIN departments d
    ON e.department_id = d.department_id;
    
  • 左1——左外連線

    SELECT employee_id,department_name
    FROM employees e LEFT JOIN departments d
    ON e.department_id = d.department_id;
    
  • 右1——右外連線

    SELECT employee_id,department_name
    FROM employees e RIGHT JOIN departments d
    ON e.department_id = d.department_id;
    
  • 左2

    SELECT employee_id,department_name
    FROM employees e LEFT JOIN departments d
    ON e.department_id = d.department_id
    WHERE d.department_id IS NULL;
    
  • 右2

    SELECT employee_id,department_name
    FROM employees e RIGHT JOIN departments d
    ON e.department_id = d.department_id
    WHERE e.department_id IS NULL;
    
  • 左3

    #左1圖UNION ALL右2圖
    #不要習慣性的加分號!
    SELECT employee_id,department_name
    FROM employees e LEFT JOIN departments d
    ON e.department_id = d.department_id
    UNION ALL
    SELECT employee_id,department_name
    FROM employees e RIGHT JOIN departments d
    ON e.department_id = d.department_id
    WHERE e.department_id IS NULL;
    
  • 右3

    #左2 UNION ALL 右二
    SELECT employee_id,department_name
    FROM employees e LEFT JOIN departments d
    ON e.department_id = d.department_id
    WHERE d.department_id IS NULL
    UNION ALL
    SELECT employee_id,department_name
    FROM employees e RIGHT JOIN departments d
    ON e.department_id = d.department_id
    WHERE e.department_id IS NULL;