回答:
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
この種のa JOIN
では、両方のテーブルの条件に一致するすべてのレコードが取得され、両方のテーブルの一致しないレコードは報告されません。
言い換えると、これINNER JOIN
は、次の単一の事実に基づいています。テーブルの両方で、一致するエントリのみをリストする必要があります。
なお、JOIN
他のせずにJOIN
キーワード(のようなINNER
、OUTER
、LEFT
、など)ですINNER JOIN
。言い換えるJOIN
と、はの構文糖質ですINNER JOIN
(参照:JOINとINNER JOINの違い)。
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 JOIN
とRIGHT OUTER JOIN
。条件が満たされた場合はどちらかのテーブルから行を返しNULL
、一致しない場合は値を返します。
言い換えると、次OUTER JOIN
の事実に基づいています。1つのテーブル(RIGHTまたはLEFT)または両方のテーブル(FULL)の一致するエントリのみをリストする必要があります。
Note that `OUTER JOIN` is a loosened form of `INNER JOIN`.
これは次の2つの条件に基づいています。
JOIN
は、同等にするために同じ名前のすべての列に対して行われます。これは本質的に理論的であるように思われ、その結果(おそらく)ほとんどのDBMSはこれをサポートすることすらしません。
これは、関連する2つのテーブルのデカルト積です。aの結果は、CROSS JOIN
ほとんどの状況で意味がありません。さらに、これはまったく必要ありません(正確には最低でも必要です)。
これは、別の形態ではないJOIN
、むしろそれは、JOIN
(INNER
、OUTER
それ自体にテーブル、等)。
JOIN
句に使用する演算子に応じて、2種類のが存在する可能性がありますJOIN
。彼らです
何のためJOIN
のタイプ(INNER
、OUTER
我々はONLY等価演算子(=)を使用している場合など)、そして我々はそれを言ってJOIN
いますEQUI JOIN
。
これは同じですEQUI JOIN
が、>、<、> =などの他のすべての演算子を許可します。
多くは両方を検討
EQUI JOIN
し、シータはJOIN
に似てINNER
、OUTER
などJOIN
の。しかし、私はそれが間違いであり、アイデアが曖昧になると強く信じています。そのためINNER JOIN
、OUTER JOIN
等は全て一方のテーブルとそのデータに接続されているEQUI JOIN
とTHETA JOIN
だけ私たちは前者では使用事業者に接続されています。繰り返しますが、
NATURAL JOIN
ある種の「特異」と見なす人はたくさんいEQUI JOIN
ます。実際、私がについて述べた最初の条件のため、それは本当ですNATURAL JOIN
。ただし、これを単にNATURAL JOIN
sだけに制限する必要はありません。INNER JOIN
s、OUTER JOIN
sなどもそうかもしれませEQUI JOIN
ん。
定義:
JOINSは、複数のテーブルから同時に結合されたデータをクエリする方法です。
RDBMSに関しては、5つのタイプの結合があります。
等価結合:等価条件に基づいて、2つのテーブルの共通レコードを結合します。技術的には、等値演算子(=)を使用して結合を行い、1つのテーブルの主キーの値と別のテーブルの外部キーの値を比較するため、結果セットには両方のテーブルの共通(一致)レコードが含まれます。実装については、INNER-JOINを参照してください。
Natural-Join: Equi-Joinの拡張バージョンで、SELECT操作で重複する列が省略されます。実装については、INNER-JOINを参照してください
非等結合:結合条件が等号演算子(=)以外で使用されている場合の等結合の逆です。
自己結合::テーブルがそれ自体と結合する結合のカスタマイズされた動作。これは通常、自己参照テーブル(または単項関係エンティティ)のクエリに必要です。実装については、INNER-JOINを参照してください。
デカルト積:条件なしで両方のテーブルのすべてのレコードをクロス結合します。技術的には、WHERE句のないクエリの結果セットを返します。
SQLの懸念と進歩に従って、3つのタイプの結合があり、すべてのRDBMS結合はこれらのタイプの結合を使用して実現できます。
INNER-JOIN: 2つのテーブルから一致した行をマージ(または結合)します。マッチングは、テーブルの一般的な列とそれらの比較操作に基づいて行われます。等価ベースの条件の場合:EQUI-JOINが実行され、それ以外の場合は非EQUI-Join。
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):両方のテーブルから一致したものと一致しないものを返します。
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;
intersect
/ except
/ union
。ここで、円は、番号付きラベルが言うように、left
&によって返される行right
join
です。AXBの画像はナンセンスです。cross join
= inner join on 1=1
&は最初の図の特殊なケースです。
UNION JOIN
。SQL:2003で廃止されました。
興味深いことに、他のほとんどの回答はこれら2つの問題に悩まされています。
私は最近このトピックに関する記事を書きました:SQLでテーブルを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
ただフィルタリングされ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を除く)。
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つの列に等価述語を作成できます。
他の回答では、この「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 ] JOIN
:JOIN
上記のように、式の左側のテーブルがユニオンに追加されます。RIGHT [ OUTER ] JOIN
:JOIN
上記のように、式の右のテーブルがユニオンに追加されます。FULL [ OUTER ] JOIN
:JOIN
上記のように、式の両方のテーブルがユニオンに追加されます。これらのすべてがキーワードと組み合わせることができる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の反対側」のいずれかと一致したかどうかに関係なく、結果に含まれることです。要するに、これはレポートのスパースデータを埋めるためです。非常に便利!
マジ?これを得た他の答えはありませんか?もちろん、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操作を実行していることがわかります。
これは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
、それらは通常言及されています。私の記事の詳細。そして、それらを説明するためにベン図の使用をやめてください。
私はペットピーチを押すつもりです:USINGキーワード。
JOINの両側の両方のテーブルの外部キーが適切に指定されている場合(つまり、「id」だけでなく、同じ名前)、これを使用できます。
SELECT ...
FROM customers JOIN orders USING (customer_id)
これは非常に実用的で読みやすく、頻繁に使用されるわけではありません。