SQLでの複数テーブル接続クエリの詳細説明

複数テーブル結合クエリ

講師:シャン・シリコンバレー・ソン・ホンカン(江湖ではマスター・コンとして知られる)
公式ウェブサイト:http://www.atguigu.com

マルチテーブル クエリ (関連クエリとも呼ばれます) は、クエリ操作を一緒に完了する 2 つ以上のテーブルを指します。
前提条件: 一緒にクエリされるこれらのテーブル間にはリレーションシップ (1 対 1、1 対多) があり、それらの間に関連フィールドが存在する必要があります。この関連フィールドには外部キーが確立されている場合と、確立されていない場合があります。たとえば、従業員テーブルと部門テーブル、これら 2 つのテーブルは「部門番号」によって関連付けられています。

1. ケースによる複数テーブル結合

1.1 事例の説明

1554974984600.png
複数のテーブルからデータを取得します。
1554975020388.png

#案例:查询员工的姓名及其部门名称
SELECT last_name, department_name
FROM employees, departments;

1554975097631.png
検索結果:

+-----------+----------------------+
| last_name | department_name      |
+-----------+----------------------+
| King      | Administration       |
| King      | Marketing            |
| King      | Purchasing           |
| King      | Human Resources      |
| King      | Shipping             |
| King      | IT                   |
| King      | Public Relations     |
| King      | Sales                |
| King      | Executive            |
| King      | Finance              |
| King      | Accounting           |
| King      | Treasury             |
...
| Gietz     | IT Support           |
| Gietz     | NOC                  |
| Gietz     | IT Helpdesk          |
| Gietz     | Government Sales     |
| Gietz     | Retail Sales         |
| Gietz     | Recruiting           |
| Gietz     | Payroll              |
+-----------+----------------------+
2889 rows in set (0.01 sec)

エラー状況を分析します。

SELECT COUNT(employee_id) FROM employees;
#输出107行

SELECT COUNT(department_id)FROM departments;
#输出27行

SELECT 107*27 FROM dual;

上記の複数テーブル クエリで発生する問題をデカルト積エラーと呼びます。

1.2 デカルト積 (または相互接続) の理解

デカルト積は数学的な演算です。2 つのセット X と Y があるとします。X と Y のデカルト積は、X と Y の可能なすべての組み合わせ、つまり、X の最初のオブジェクトと Y の 2 番目のオブジェクトの可能なすべての組み合わせになります。組み合わせの数は、2 つのセット内の要素の数の積です。

SQL92 では、デカルト積はクロス結合とも呼ばれ、英語では ** CROSS JOIN ** となります。SQL99 では、CROSS JOIN は相互接続を表すためにも使用されます。この機能は、2 つのテーブルが関連していない場合でも、任意のテーブルを結合することです。MySQL では、デカルト積は次の状況で発生します。

#查询员工姓名和所在部门名称
SELECT last_name,department_name FROM employees,departments;
SELECT last_name,department_name FROM employees CROSS JOIN departments;
SELECT last_name,department_name FROM employees INNER JOIN departments;
SELECT last_name,department_name FROM employees JOIN departments;

1.3 事例分析と問題解決

  • デカルト積誤差は、次の状況で発生します
    • 複数のテーブルの結合条件(または関連付け条件)を省略します。
    • 結合条件(または関連付け条件)が無効です
    • すべてのテーブルのすべての行は相互に接続されています
  • デカルト積を避けるために、WHERE に有効な結合条件を追加できます。
  • 接続条件を追加した後のクエリ構文は次のようになります。
SELECT	table1.column, table2.column
FROM	table1, table2
WHERE	table1.column1 = table2.column2;  #连接条件
  • WHERE句に結合条件を記述します。
  • 正しい書き方:
#案例:查询员工的姓名及其部门名称
SELECT last_name, department_name
FROM employees, departments
WHERE employees.department_id = departments.department_id;
  • テーブル内に同一の列がある場合は、列名の前にテーブル名を付けます。

2. マルチテーブルクエリ分類の説明

カテゴリ 1: 等価接続と非等価接続

等結合

1554975496900.png

SELECT employees.employee_id, employees.last_name, employees.department_id, departments.department_id, departments.location_id
FROM   employees, departments
WHERE  employees.department_id = departments.department_id;

1554975522600.png
1554975526339.png
拡張 1: 複数の接続条件と AND 演算子
1554975606231.png
拡張 2: 重複する列名の区別

  • 複数のテーブルに同一の列がある場合は、列名の前にテーブル名を付ける必要があります。
  • 異なるテーブル内の同じ列名の列は、テーブル名によって区別できます。
SELECT employees.last_name, departments.department_name,employees.department_id
FROM employees, departments
WHERE employees.department_id = departments.department_id;

拡張 3: テーブルのエイリアス

  • エイリアスを使用するとクエリを簡素化できます。
  • 列名の前にテーブル名のプレフィックスを使用すると、クエリの効率が向上します。
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id
FROM   employees e , departments d
WHERE  e.department_id = d.department_id;

テーブルのエイリアスを使用する場合、そのエイリアスはクエリ フィールドとフィルター条件でのみ使用でき、元のテーブル名は使用できないことに注意してください。使用しないとエラーが報告されます。
Alibaba 開発仕様:
[必須] データベース内のテーブル レコードに対するクエリと変更の場合、複数のテーブルが関係する限り、テーブルの別名 (またはテーブル名) を列名の前に修飾する必要があります。
注: 複数のテーブルでレコードのクエリ、レコードの更新、またはレコードの削除を行う場合、操作列にテーブルを修飾する別名 (またはテーブル名) がなく、操作列が複数のテーブルに存在する場合、例外がスローされます。
正例: select t1.name from table_first as t1, table_second as t2 where t1.id=t2.id;
反例: ある業務では、複数テーブルの関連付けクエリ文にはテーブルの別名(またはテーブル)の制限がないため、 name), 2 年間正常に実行された後、同じ名前のフィールドが最近テーブルに追加されました。プレリリース環境でデータベースが変更された後、オンライン クエリ ステートメントで 1052 例外が発生しました: 列 'name' inフィールドリストがあいまいです。
拡張 4: 複数のテーブルを接続する
1554978354431.png
** 概要: n 個のテーブルを接続するには、少なくとも n-1 個の接続条件が必要です。**たとえば、3 つのテーブルを結合するには、少なくとも 2 つの結合条件が必要です。
演習: 従業員の姓、部門名、市区町村をクエリする

非等結合

1554978442447.png

SELECT e.last_name, e.salary, j.grade_level
FROM   employees e, job_grades j
WHERE  e.salary BETWEEN j.lowest_sal AND j.highest_sal;

1554978477013.png

カテゴリ 2: 自己接続と非自己接続

1554978514321.png

  • table1 と table2 が本質的に同じテーブルである場合、異なる意味を表す別名を使用して 2 つのテーブルに仮想化されているだけです。次に、2 つのテーブルが内部結合、外部結合、その他のクエリを実行します。

タイトル: 従業員テーブルをクエリし、「Xxx は Xxx のために機能します」を返します。

SELECT CONCAT(worker.last_name ,' works for ', manager.last_name)
FROM   employees worker, employees manager
WHERE  worker.manager_id = manager.employee_id ;

1554978684947.png
1554978690764.png

カテゴリ 3: 内部結合と外部結合

外部結合では、条件を満たすレコードをクエリするだけでなく、一方の条件を満たさないレコードをクエリすることもできます。
1554978955659.png

  • 内部結合: 同じ列を持つ 3 つ以上のテーブルの行をマージします。結果セットには、あるテーブルの別のテーブルと一致しない行は含まれません。
  • 外部結合: 2 つのテーブルの接続プロセス中に、結合条件を満たす行を返すだけでなく、条件を満たさない左側 (または右側) のテーブルの行も返します。このタイプの結合は左 (または右) 外部結合一致する行がない場合、結果テーブルの対応する列は NULL になります。
  • 左外部結合の場合、結合条件の左側のテーブルをマスターテーブル、右側のテーブルをスレーブテーブルとも呼びます。右外部結合の場合、結合条件の右側のテーブルをマスターテーブル、左側のテーブルをスレーブテーブルとも呼びます。

3. SQL99 構文を使用して複数テーブル クエリを実装する

3.1 基本的な構文

  • JOIN…ON 句を使用して結合を作成するための構文構造:
SELECT table1.column, table2.column,table3.column
FROM table1
JOIN table2 ON table1 和 table2 的连接条件
JOIN table3 ON table2 和 table3 的连接条件

そのネストされたロジックは、使用する FOR ループに似ています。

for t1 in table1:
    for t2 in table2:
       if condition1:
           for t3 in table3:
              if condition2:
                  output t1 + t2 + t3
  • 構文の説明:
    • ON 句を使用して追加の結合条件を指定できます
    • この結合条件は他の条件とは別のものです。
    • ON 句を使用すると、ステートメントが読みやすくなります
    • キーワード JOIN、INNER JOIN、および CROSS JOIN は同じ意味を持ち、すべて内部結合を表します。

3.2 INNER JOIN の実装

  • 文法:
SELECT 字段列表
FROM A表 INNER JOIN B表
ON 关联条件
WHERE 等其他子句;

質問1:

SELECT e.employee_id, e.last_name, e.department_id, 
d.department_id, d.location_id
FROM employees e JOIN departments d
ON (e.department_id = d.department_id);

1554979073996.png
1554979079395.png
質問2:

SELECT employee_id, city, department_name
FROM employees e 
JOIN departments d
ON d.department_id = e.department_id 
JOIN locations l
ON d.location_id = l.location_id;

1554979110008.png
1554979115642.png

3.3 OUTER JOINの実装

3.3.1 左外部結合
  • 文法:
#实现查询结果是A
SELECT 字段列表
FROM A表 LEFT JOIN B表sq
ON 关联条件
WHERE 等其他子句;
  • 例:
SELECT e.last_name, e.department_id, d.department_name
FROM   employees e
LEFT OUTER JOIN departments d
ON   (e.department_id = d.department_id) ;

1554979200961.png

3.3.2 右外部結合
  • 文法:
#实现查询结果是B
SELECT 字段列表
FROM A表 RIGHT JOIN B表
ON 关联条件
WHERE 等其他子句;
  • 例:
SELECT e.last_name, e.department_id, d.department_name
FROM   employees e
RIGHT OUTER JOIN departments d
ON    (e.department_id = d.department_id) ;

1554979243194.png
LEFT JOIN と RIGHT JOIN は SQL99 以降の標準にのみ存在しますが、SQL92 には存在せず、(+) でのみ表すことができることに注意してください。

3.3.3 完全外部結合
  • 完全外部結合の結果 = 左右のテーブルに一致するデータ + 左側のテーブルに一致するデータなし + 右側のテーブルに一致するデータなし。
  • SQL99 は完全な外部接続をサポートしています。これを実現するには、FULL JOIN または FULL OUTER JOIN を使用します。
  • MySQL は FULL JOIN をサポートしていませんが、代わりに LEFT JOIN UNION RIGHT 結合を使用できることに注意してください

4. UNIONの使用

クエリ結果のマージUNION キーワードを使用すると、複数の SELECT ステートメントを指定し、その結果を 1 つの結果セットに結合できます。マージする場合、2 つのテーブルに対応する列の数とデータ型が同じであり、相互に対応している必要があります。各 SELECT ステートメントは、UNION または UNION ALL キーワードで区切られます。
構文形式:

SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2

UNION 演算子
1554979317187.png
UNION 演算子は、2 つのクエリの結果セットの和集合を返し、重複レコードを削除します。
UNION ALL 演算子
1554979343634.png
UNION ALL 演算子は、2 つのクエリの結果セットの結合を返します。2 つの結果セットの重複部分は重複排除されません。
注: UNION ALL ステートメントは、UNION ステートメントよりも必要なリソースが少なくなります。データを結合した結果のデータに重複データがないことが明らかな場合、または重複データを削除する必要がない場合は、UNION ALL ステートメントを使用してデータ クエリの効率を向上させてみてください。
例: 部門番号が 90 を超える従業員情報、または電子メール アドレスに a が含まれる従業員情報を照会します。
データが重複する可能性があるため、UNION を使用します。

#方式1
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;
#方式2
SELECT * FROM employees  WHERE email LIKE '%a%'
UNION
SELECT * FROM employees  WHERE department_id>90;

例:中国の男性ユーザー情報と米国の中年男性ユーザー情報をクエリする場合、
重複データがないためUNION ALLを使用することでクエリ効率が向上します。

SELECT id,cname FROM t_chinamale WHERE csex='男'
UNION ALL
SELECT id,tname FROM t_usmale WHERE tGender='male';

5. 7 つの SQL JOINS の実装

1554979255233.png

5.1 コードの実装

#中图:内连接 A∩B
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`;
#左上图:左外连接
SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`;
#右上图:右外连接
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;
#左中图:A - A∩B
SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
#右中图:B-A∩B
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL
#左下图:满外连接
# 左中图 + 右上图  A∪B
SELECT employee_id,last_name,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,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;
#右下图
#左中图 + 右中图  A ∪B- A∩B 或者 (A -  A∩B) ∪ (B - A∩B)
SELECT employee_id,last_name,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,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL

5.2 構文形式の概要

  • 中左の写真
#实现A -  A∩B
select 字段列表
from A表 left join B表
on 关联条件
where 从表关联字段 is null and 等其他子句;
  • 中右の写真
#实现B -  A∩B
select 字段列表
from A表 right join B表
on 关联条件
where 从表关联字段 is null and 等其他子句;
  • 左下の写真
#实现查询结果是A∪B
#用左外的A,union 右外的B
select 字段列表
from A表 left join B表
on 关联条件
where 等其他子句

union 

select 字段列表
from A表 right join B表
on 关联条件
where 等其他子句;
  • 右下の写真
#实现A∪B -  A∩B  或   (A -  A∩B) ∪ (B - A∩B)
#使用左外的 (A -  A∩B)  union 右外的(B - A∩B)
select 字段列表
from A表 left join B表
on 关联条件
where 从表关联字段 is null and 等其他子句

union

select 字段列表
from A表 right join B表
on 关联条件
where 从表关联字段 is null and 等其他子句

注:
結合テーブルの数を制御する必要があります。複数テーブルの結合は、ネストされた for ループと同等であり、大量のリソースを消費し、SQL クエリのパフォーマンスを著しく低下させるため、不必要なテーブルを結合しないでください。多くの DBMS では、最大結合テーブルにも制限があります。【必須】3テーブル以上の結合は禁止します。結合する必要があるフィールドのデータ型は完全に一貫している必要があり、複数のテーブルに関連するクエリを実行する場合は、関連するフィールドにインデックスが必要であることが保証されます。注: 2 つのテーブルを結合する場合でも、テーブルのインデックスと SQL のパフォーマンスに注意を払う必要があります。出典:Alibaba「Java開発マニュアル」


おすすめ

転載: blog.csdn.net/hansome_hong/article/details/127473607