SQL JOINとさまざまなタイプのJOIN


244

SQL JOINとは何ですか?異なるタイプとは何ですか?

回答:


330

W3schoolsからのイラスト:


INNER JOIN-両方のテーブルの条件に一致するレコードのみ


LEFT JOIN-テーブル2の条件に一致するレコードと組み合わせた、テーブル1のすべてのレコード


RIGHT JOIN-テーブル2のすべてのレコードと、条件に一致するテーブル1のレコード


FULL OUTER JOIN-左外部結合と右外部結合の組み合わせがON句と一致していますが、両方のテーブルを保持しています



27
@KNU w3foolsは、写真のアイデアをどこから取ったかを評価する必要があります。参照してくださいSQLの可視化が参加するジェフ・アトウッドで(はい、SO共著1)とLigaya Turmelleによってリンク先の記事ジェフのアイデアを持って、それをexplanded。
ypercubeᵀᴹ

2
@aviの左と右の結合は似ていますが、結合の基になっているプラ​​イマリテーブルがわからない場合は、
Anup

2
@philipxy:それは奇妙な定義です(たとえあなたが正しいとしても)。しかし、私はむしろ逆に行き、クロス結合から始めて、その上に内部結合を「構築」します。結局のところ、クロスジョインの単なる概念は、これらの非公式で不正確なベン図の視覚化を無効にします...
Lukas Eder

1
これらの画像は、ユニオンが完全な外部結合と同じであり、交差が内部結合と同じであることを示しているようです。これは、私の知る限り正しくありません。
mightyWOZ 2017年

1
@DevDave、一般的な信念に反するため-写真は千の言葉の価値はありません。次の答えを見てください。
hyankov 2017年

248

なにSQL JOIN

SQL JOIN 2つ以上のデータベーステーブルからデータを取得するメソッドです。

異なるSQL JOINのは何ですか?

合計5つJOINのがあります。彼らです :

  1. JOIN or INNER JOIN
  2. OUTER JOIN

     2.1 LEFT OUTER JOIN or LEFT JOIN
     2.2 RIGHT OUTER JOIN or RIGHT JOIN
     2.3 FULL OUTER JOIN or FULL JOIN

  3. NATURAL JOIN
  4. CROSS JOIN
  5. SELF JOIN

1. JOINまたはINNER JOIN:

この種のa JOINでは、両方のテーブルの条件に一致するすべてのレコードが取得され、両方のテーブルの一致しないレコードは報告されません。

言い換えると、これINNER JOINは、次の単一の事実に基づいています。テーブルの両方で、一致するエントリのみをリストする必要があります。

なお、JOIN他のせずにJOINキーワード(のようなINNEROUTERLEFT、など)ですINNER JOIN。言い換えるJOINと、はの構文糖質ですINNER JOIN(参照:JOINとINNER JOINの違い)。

2.外部結合:

OUTER JOIN 取得する

一方のテーブルの一致した行ともう一方のテーブルのすべての行、またはすべてのテーブルのすべての行(一致するかどうかは関係ありません)。

外部結合には次の3種類があります。

2.1 LEFT OUTER JOINまたはLEFT JOIN

この結合は、右のテーブルの一致する行とともに、左のテーブルのすべての行を返します。右側のテーブルに一致する列がない場合は、NULL値を返します。

2.2 RIGHT OUTER JOINまたはRIGHT JOIN

これJOINにより、左側のテーブルの一致する行とともに、右側のテーブルのすべての行が返されます。左側のテーブルに一致する列がない場合、NULL値が返されます。

2.3 FULL OUTER JOINまたはFULL JOIN

これは、JOIN組み合わせLEFT OUTER JOINRIGHT OUTER JOIN。条件が満たされた場合はどちらかのテーブルから行を返しNULL、一致しない場合は値を返します。

言い換えると、次OUTER JOINの事実に基づいています。1つのテーブル(RIGHTまたはLEFT)または両方のテーブル(FULL)の一致するエントリのみをリストする必要があります。

Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.

3.自然結合:

これは次の2つの条件に基づいています。

  1. これJOINは、同等にするために同じ名前のすべての列に対して行われます。
  2. 結果から重複する列を削除します。

これは本質的に理論的であるように思われ、その結果(おそらく)ほとんどのDBMSはこれをサポートすることすらしません。

4. CROSS JOIN:

これは、関連する2つのテーブルのデカルト積です。aの結果は、CROSS JOINほとんどの状況で意味がありません。さらに、これはまったく必要ありません(正確には最低でも必要です)。

5.自己結合:

これは、別の形態ではないJOIN、むしろそれは、JOININNEROUTERそれ自体にテーブル、等)。

演算子に基づくJOIN

JOIN句に使用する演算子に応じて、2種類のが存在する可能性がありますJOIN。彼らです

  1. Equi JOIN
  2. シータジョイン

1. Equi JOIN:

何のためJOINのタイプ(INNEROUTER我々はONLY等価演算子(=)を使用している場合など)、そして我々はそれを言ってJOINいますEQUI JOIN

2. Theta JOIN:

これは同じですEQUI JOINが、>、<、> =などの他のすべての演算子を許可します。

多くは両方を検討EQUI JOINし、シータはJOINに似てINNEROUTER などJOINの。しかし、私はそれが間違いであり、アイデアが曖昧になると強く信じています。そのためINNER JOINOUTER JOIN等は全て一方のテーブルとそのデータに接続されているEQUI JOINTHETA JOINだけ私たちは前者では使用事業者に接続されています。

繰り返しますが、NATURAL JOINある種の「特異」と見なす人はたくさんいEQUI JOINます。実際、私がについて述べた最初の条件のため、それは本当ですNATURAL JOIN。ただし、これを単にNATURAL JOINsだけに制限する必要はありません。INNER JOINs、OUTER JOINsなどもそうかもしれませEQUI JOINん。


2
比較的新しいLATERAL JOINがあります.. SELECT * FROM r1、LATERAL fx(r1)
Pavel Stehule

13
これは理にかなっているように思われますが、有用な情報を伝えるような方法で「SQL結合とは」に回答することはないと思います。全体としての答えは、結合をすでに理解している人のために書かれたリファレンスであり、それらの質問をしているような人のためではありません。また、(信頼できる回答をする場合に適切である)その主張をサポートするため、および外部リソースを介して追加の説明を提供するための両方で、参照を省略しています。新しいSQLユーザーをリンクするための信頼できる回答を書こうとしている場合は、特に「結合とは何か」の部分に少し空白を入れる価値があるかもしれません。
クレイグリンガー2013

いくつかの例を提供できますか?
avi

67

定義:


JOINSは、複数のテーブルから同時に結合されたデータをクエリする方法です。

結合のタイプ:


RDBMSに関しては、5つのタイプの結合があります。

  • 等価結合:等価条件に基づいて、2つのテーブルの共通レコードを結合します。技術的には、等値演算子(=)を使用して結合を行い、1つのテーブルの主キーの値と別のテーブルの外部キーの値を比較するため、結果セットには両方のテーブルの共通(一致)レコードが含まれます。実装については、INNER-JOINを参照してください。

  • Natural-Join: Equi-Joinの拡張バージョンで、SELECT操作で重複する列が省略されます。実装については、INNER-JOINを参照してください

  • 非等結合:結合条件が等号演算子(=)以外で使用されている場合の等結合の逆です。

  • 自己結合::テーブルがそれ自体と結合する結合のカスタマイズされた動作。これは通常、自己参照テーブル(または単項関係エンティティ)のクエリに必要です。実装については、INNER-JOINを参照してください。

  • デカルト積:条件なしで両方のテーブルのすべてのレコードをクロス結合します。技術的には、WHERE句のないクエリの結果セットを返します。

SQLの懸念と進歩に従って、3つのタイプの結合があり、すべてのRDBMS結合はこれらのタイプの結合を使用して実現できます。

  1. INNER-JOIN: 2つのテーブルから一致した行をマージ(または結合)します。マッチングは、テーブルの一般的な列とそれらの比較操作に基づいて行われます。等価ベースの条件の場合:EQUI-JOINが実行され、それ以外の場合は非EQUI-Join。

  2. OUTER-JOIN: 2つのテーブルの一致した行と一致しない行をNULL値でマージ(または結合)します。ただし、一致しない行の選択をカスタマイズできます。たとえば、サブタイプによって左のテーブルまたは第2のテーブルから一致しない行を選択できます:LEFT OUTER JOINおよびRIGHT OUTER JOIN。

    2.1。LEFT Outer JOIN(別名、LEFT-JOIN):2つのテーブルから一致した行を返し、LEFTテーブル(つまり、最初のテーブル)からは一致しなかった行のみを返します。

    2.2。RIGHT Outer JOIN(別名、RIGHT-JOIN):2つのテーブルから一致した行を返し、RIGHTテーブルからのみ不一致を返します。

    2.3。FULL OUTER JOIN(別名OUTER JOIN):両方のテーブルから一致したものと一致しないものを返します。

  3. CROSS-JOIN:この結合は、マージ/結合ではなく、デカルト積を実行します。

ここに画像の説明を入力してください 注:Self-JOINは、要件に基づいてINNER-JOIN、OUTER-JOIN、CROSS-JOINのいずれかによって実現できますが、テーブルはそれ自体と結合する必要があります。

詳細については:

例:

1.1:INNER-JOIN:等結合の実装

SELECT  *
FROM Table1 A 
 INNER JOIN Table2 B ON A.<Primary-Key> =B.<Foreign-Key>;

1.2:INNER-JOIN:Natural-JOINの実装

Select A.*, B.Col1, B.Col2          --But no B.ForeignKeyColumn in Select
 FROM Table1 A
 INNER JOIN Table2 B On A.Pk = B.Fk;

1.3:非等価結合実装によるINNER-JOIN

Select *
 FROM Table1 A INNER JOIN Table2 B On A.Pk <= B.Fk;

1.4:SELF-JOINによるINNER-JOIN

Select *
 FROM Table1 A1 INNER JOIN Table1 A2 On A1.Pk = A2.Fk;

2.1:OUTER JOIN(完全外部結合)

Select *
 FROM Table1 A FULL OUTER JOIN Table2 B On A.Pk = B.Fk;

2.2:左結合

Select *
 FROM Table1 A LEFT OUTER JOIN Table2 B On A.Pk = B.Fk;

2.3:右結合

Select *
 FROM Table1 A RIGHT OUTER JOIN Table2 B On A.Pk = B.Fk;

3.1:クロス結合

Select *
 FROM TableA CROSS JOIN TableB;

3.2:CROSS JOIN-自己結合

Select *
 FROM Table1 A1 CROSS JOIN Table1 A2;

//または//

Select *
 FROM Table1 A1,Table1 A2;

ラベル「表1」及び「表2」&不適切である下ラベルは、それらがイラストからのものであるのintersect/ except/ union。ここで、円は、番号付きラベルが言うように、left&によって返される行right joinです。AXBの画像はナンセンスです。cross join= inner join on 1=1&は最初の図の特殊なケースです。
philipxy 2018年

SQL-92がを定義していることに言及する価値がありますUNION JOIN。SQL:2003で廃止されました。
インパラー

40

興味深いことに、他のほとんどの回答はこれら2つの問題に悩まされています。

私は最近このトピックに関する記事を書きました:SQLテーブルをJOINするためのさまざまな方法へのおそらく不完全で包括的なガイドです。ここで要約します。

何よりもまず、JOINはデカルト製品です

JOINは2つの結合されたテーブルの間にデカルト積を作成するため、ベン図がそれらを非常に不正確に説明するのはこのためです。ウィキペディアはそれをうまく説明しています:

ここに画像の説明を入力してください

デカルト積のSQL構文はCROSS JOINです。例えば:

SELECT *

-- This just generates all the days in January 2017
FROM generate_series(
  '2017-01-01'::TIMESTAMP,
  '2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
  INTERVAL '1 day'
) AS days(day)

-- Here, we're combining all days with all departments
CROSS JOIN departments

これは、1つのテーブルのすべての行を他のテーブルのすべての行と結合します。

ソース:

+--------+   +------------+
| day    |   | department |
+--------+   +------------+
| Jan 01 |   | Dept 1     |
| Jan 02 |   | Dept 2     |
| ...    |   | Dept 3     |
| Jan 30 |   +------------+
| Jan 31 |
+--------+

結果:

+--------+------------+
| day    | department |
+--------+------------+
| Jan 01 | Dept 1     |
| Jan 01 | Dept 2     |
| Jan 01 | Dept 3     |
| Jan 02 | Dept 1     |
| Jan 02 | Dept 2     |
| Jan 02 | Dept 3     |
| ...    | ...        |
| Jan 31 | Dept 1     |
| Jan 31 | Dept 2     |
| Jan 31 | Dept 3     |
+--------+------------+

テーブルのコンマ区切りリストを記述するだけでも、同じ結果が得られます。

-- CROSS JOINing two tables:
SELECT * FROM table1, table2

INNER JOIN(シータジョイン)

INNER JOINただフィルタリングされCROSS JOINたフィルタ述語が呼び出される場合Theta、リレーショナル代数に。

例えば:

SELECT *

-- Same as before
FROM generate_series(
  '2017-01-01'::TIMESTAMP,
  '2017-01-01'::TIMESTAMP + INTERVAL '1 month -1 day',
  INTERVAL '1 day'
) AS days(day)

-- Now, exclude all days/departments combinations for
-- days before the department was created
JOIN departments AS d ON day >= d.created_at

キーワードINNERはオプションです(MS Accessを除く)。

結果の例については記事をご覧ください

EQUI JOIN

Theta-JOINの特別な種類は、私たちが最もよく使用するequi JOINです。述語は、あるテーブルの主キーを別のテーブルの外部キーと結合します。説明のためにSakilaデータベースを使用すると、次のように記述できます。

SELECT *
FROM actor AS a
JOIN film_actor AS fa ON a.actor_id = fa.actor_id
JOIN film AS f ON f.film_id = fa.film_id

これはすべての俳優と映画を組み合わせたものです。

または、一部のデータベース:

SELECT *
FROM actor
JOIN film_actor USING (actor_id)
JOIN film USING (film_id)

このUSING()構文では、JOIN操作のテーブルのいずれかの側に存在する必要がある列を指定し、これら2つの列に等価述語を作成できます。

NATURAL JOIN

他の回答では、この「JOINタイプ」を個別にリストしていますが、それは意味がありません。これは、theta-JOINまたはINNER JOINの特殊なケースである、equi JOINの構文糖形式です。NATURAL JOIN は、結合される両方のテーブルに共通するすべての列を収集し、それらの列を結合するだけUSING()です。(SakilaデータベースのLAST_UPDATE列のような)偶発的な一致のため、これはほとんど役に立ちません。

構文は次のとおりです。

SELECT *
FROM actor
NATURAL JOIN film_actor
NATURAL JOIN film

外部結合

これOUTER JOINは、いくつかのデカルト積をINNER JOIN作成するUNIONのとは少し異なります。我々は書ける:

-- Convenient syntax:
SELECT *
FROM a LEFT JOIN b ON <predicate>

-- Cumbersome, equivalent syntax:
SELECT a.*, b.*
FROM a JOIN b ON <predicate>
UNION ALL
SELECT a.*, NULL, NULL, ..., NULL
FROM a
WHERE NOT EXISTS (
  SELECT * FROM b WHERE <predicate>
)

誰も後者を書きたくないので、書きますOUTER JOIN(通常はデータベースによって最適化されます)。

と同様INNERに、キーワードOUTERはここではオプションです。

OUTER JOIN 3つのフレーバーがあります。

  • LEFT [ OUTER ] JOINJOIN上記のように、式の左側のテーブルがユニオンに追加されます。
  • RIGHT [ OUTER ] JOINJOIN上記のように、式の右のテーブルがユニオンに追加されます。
  • FULL [ OUTER ] JOINJOIN上記のように、式の両方のテーブルがユニオンに追加されます。

これらのすべてがキーワードと組み合わせることができるUSING()か、とNATURAL私は実際のための実世界のユースケースを持っていたNATURAL FULL JOIN最近

代替構文

OracleとSQL Serverには、いくつかの歴史的で非推奨の構文があります。これらはOUTER JOIN、SQL標準がこの構文を持つ前にすでにサポートされていました。

-- Oracle
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)

-- SQL Server
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id *= fa.actor_id
AND fa.film_id *= f.film_id

そうは言っても、この構文は使用しないでください。これをここにリストアップするだけで、古いブログ投稿/レガシーコードからそれを認識できます。

分割 OUTER JOIN

これを知っている人はほとんどいませんが、SQL標準ではパーティション分割が指定されていますOUTER JOIN(Oracleはそれを実装しています)。次のように書くことができます:

WITH

  -- Using CONNECT BY to generate all dates in January
  days(day) AS (
    SELECT DATE '2017-01-01' + LEVEL - 1
    FROM dual
    CONNECT BY LEVEL <= 31
  ),

  -- Our departments
  departments(department, created_at) AS (
    SELECT 'Dept 1', DATE '2017-01-10' FROM dual UNION ALL
    SELECT 'Dept 2', DATE '2017-01-11' FROM dual UNION ALL
    SELECT 'Dept 3', DATE '2017-01-12' FROM dual UNION ALL
    SELECT 'Dept 4', DATE '2017-04-01' FROM dual UNION ALL
    SELECT 'Dept 5', DATE '2017-04-02' FROM dual
  )
SELECT *
FROM days 
LEFT JOIN departments 
  PARTITION BY (department) -- This is where the magic happens
  ON day >= created_at

結果の一部:

+--------+------------+------------+
| day    | department | created_at |
+--------+------------+------------+
| Jan 01 | Dept 1     |            | -- Didn't match, but still get row
| Jan 02 | Dept 1     |            | -- Didn't match, but still get row
| ...    | Dept 1     |            | -- Didn't match, but still get row
| Jan 09 | Dept 1     |            | -- Didn't match, but still get row
| Jan 10 | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 11 | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 12 | Dept 1     | Jan 10     | -- Matches, so get join result
| ...    | Dept 1     | Jan 10     | -- Matches, so get join result
| Jan 31 | Dept 1     | Jan 10     | -- Matches, so get join result

ここでのポイントは、結合の分割された側からのすべての行はJOIN、「JOINの反対側」のいずれかと一致したかどうかに関係なく、結果に含まれることです。要するに、これはレポートのスパースデータを埋めるためです。非常に便利!

SEMI JOIN

マジ?これを得た他の答えはありませんか?もちろん、SQLにはネイティブ構文がないため、残念ながら(以下のANTI JOINのように)ありません。しかし、IN()and を使用してEXISTS()、たとえば、映画で出演したすべての俳優を見つけることができます。

SELECT *
FROM actor a
WHERE EXISTS (
  SELECT * FROM film_actor fa
  WHERE a.actor_id = fa.actor_id
)

WHERE a.actor_id = fa.actor_idセミは、結合述語として述語が動作します。信じられない場合は、Oracleなどで実行計画を確認してください。データベースがEXISTS()述語ではなくSEMI JOIN操作を実行していることがわかります。

ここに画像の説明を入力してください

ANTI JOIN

これはSEMI JOINの正反対です(ただし、重要な注意事項があるため、使用しないようにNOT IN注意してください)。

映画のない俳優は以下のとおりです。

SELECT *
FROM actor a
WHERE NOT EXISTS (
  SELECT * FROM film_actor fa
  WHERE a.actor_id = fa.actor_id
)

一部の人々(特にMySQLの人々)も、次のようにANTI JOINを記述します。

SELECT *
FROM actor a
LEFT JOIN film_actor fa
USING (actor_id)
WHERE film_id IS NULL

歴史的な理由はパフォーマンスだと思います。

横方向の結合

OMG、これはかっこいい。それについて言及するのは私だけですか?ここにクールなクエリがあります:

SELECT a.first_name, a.last_name, f.*
FROM actor AS a
LEFT OUTER JOIN LATERAL (
  SELECT f.title, SUM(amount) AS revenue
  FROM film AS f
  JOIN film_actor AS fa USING (film_id)
  JOIN inventory AS i USING (film_id)
  JOIN rental AS r USING (inventory_id)
  JOIN payment AS p USING (rental_id)
  WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
  GROUP BY f.film_id
  ORDER BY revenue DESC
  LIMIT 5
) AS f
ON true

それは俳優ごとのトップ5の収益を生み出す映画を見つけるでしょう。TOP-N-per-somethingクエリが必要なときはLATERAL JOINいつでも、あなたの友達になります。あなたがSQL Serverの人なら、あなたはJOIN名前の下でこのタイプを知っていますAPPLY

SELECT a.first_name, a.last_name, f.*
FROM actor AS a
OUTER APPLY (
  SELECT f.title, SUM(amount) AS revenue
  FROM film AS f
  JOIN film_actor AS fa ON f.film_id = fa.film_id
  JOIN inventory AS i ON f.film_id = i.film_id
  JOIN rental AS r ON i.inventory_id = r.inventory_id
  JOIN payment AS p ON r.rental_id = p.rental_id
  WHERE fa.actor_id = a.actor_id -- JOIN predicate with the outer query!
  GROUP BY f.film_id
  ORDER BY revenue DESC
  LIMIT 5
) AS f

のでOK、のは、浮気おそらくというLATERAL JOINか、APPLY表現が実際にいくつかの行を生成し、「相関サブクエリ」です。しかし、「相関サブクエリ」を許可する場合は、次のことについて話すこともできます...

マルチセット

これは実際にはOracleとInformix(私の知る限り)によってのみ実装されていますが、配列やXMLを使用してPostgreSQLで、XMLを使用してSQL Serverでエミュレートできます。

MULTISET相関サブクエリを作成し、結果の行セットを外部クエリにネストします。次のクエリは、すべての俳優を選択し、各俳優がネストされたコレクションに映画を収集します。

SELECT a.*, MULTISET (
  SELECT f.*
  FROM film AS f
  JOIN film_actor AS fa USING (film_id)
  WHERE a.actor_id = fa.actor_id
) AS films
FROM actor

見てきたように、JOINの種類は「退屈」INNER、「、」以外にもOUTERありCROSS JOIN、それらは通常言及されています。私の記事の詳細。そして、それらを説明するためにベン図の使用をやめてください。


等結合は、シータが等しい場合のシータ結合の特殊なケースです。シータ結合は、内部結合の特別なケースに似ています。オンは、それぞれの列のシータ比較オンです。Coddが定義した数十年後、教科書はtheta joinを内部結合の類似である一般化として誤って定義しました。
philipxy 2018年

@philipxy:回答で変更すべき具体的なことはありますか?編集を提案できます...
Lukas Eder

10

私の考えでは、言葉よりもわかりやすいイラストを作成しました。 説明のSQL結合テーブル


@NirajサークルAとBにはAとBの行が含まれていません。クレジットなしで他の場所から盲目的にコピーされます。クロス結合は内部結合の場合に含まれ、1 = 1の内部結合です。画像のこれらの部分はどのように「完璧」ですか?
philipxy 2018年

@philipxy申し訳ありませんが、他の場所からコピーされてもかまいません。上の画像でどちらが正しくないのかわかりません。これは私にとっては大丈夫です。クロス結合についてはここでは説明しません。これは、インナー...参加には含まれていません
Niraj

-3

私はペットピーチを押すつもりです:USINGキーワード。

JOINの両側の両方のテーブルの外部キーが適切に指定されている場合(つまり、「id」だけでなく、同じ名前)、これを使用できます。

SELECT ...
FROM customers JOIN orders USING (customer_id)

これは非常に実用的で読みやすく、頻繁に使用されるわけではありません。


2
これは質問の答えにはなりません。これは、質問または回答のいずれかのコメントとして属します。
TylerH 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.