それを読んだ後、これは明示的SQL結合と暗黙的SQL結合の複製ではありません。答えは関連している(または同じ)場合もありますが、質問は異なります。
違いは何ですか?それぞれに何を入れるべきですか?
理論を正しく理解していれば、クエリオプティマイザーは両方を同じ意味で使用できるはずです。
それを読んだ後、これは明示的SQL結合と暗黙的SQL結合の複製ではありません。答えは関連している(または同じ)場合もありますが、質問は異なります。
違いは何ですか?それぞれに何を入れるべきですか?
理論を正しく理解していれば、クエリオプティマイザーは両方を同じ意味で使用できるはずです。
回答:
彼らは同じものではありません。
次のクエリを検討してください。
SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345
そして
SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
AND Orders.ID = 12345
1つ目は、注文番号とそれに対応する注文番号(ある場合)を返し12345
ます。2番目はすべての注文を返しますが、注文のみが12345
関連付けられた行を持ちます。
を使用するINNER JOIN
と、句は実質的に同等になります。ただし、機能的に同じであっても、同じ結果が得られるというだけでは、2種類の句の意味が同じであるとは限りません。
外部結合の問題
a。WHERE
句:後入社。結合が行われた後、レコードはフィルタリングされます。
b。ON
句- 参加する前。結合する前に(右側のテーブルの)レコードがフィルターされます。これは結果としてnullになる可能性があります(OUTER結合以降)。
例:以下の表を検討してください。
1. documents:
| id | name |
--------|-------------|
| 1 | Document1 |
| 2 | Document2 |
| 3 | Document3 |
| 4 | Document4 |
| 5 | Document5 |
2. downloads:
| id | document_id | username |
|------|---------------|----------|
| 1 | 1 | sandeep |
| 2 | 1 | simi |
| 3 | 2 | sandeep |
| 4 | 2 | reya |
| 5 | 3 | simi |
a)内側のWHERE
句:
SELECT documents.name, downloads.id
FROM documents
LEFT OUTER JOIN downloads
ON documents.id = downloads.document_id
WHERE username = 'sandeep'
For above query the intermediate join table will look like this.
| id(from documents) | name | id (from downloads) | document_id | username |
|--------------------|--------------|---------------------|-------------|----------|
| 1 | Document1 | 1 | 1 | sandeep |
| 1 | Document1 | 2 | 1 | simi |
| 2 | Document2 | 3 | 2 | sandeep |
| 2 | Document2 | 4 | 2 | reya |
| 3 | Document3 | 5 | 3 | simi |
| 4 | Document4 | NULL | NULL | NULL |
| 5 | Document5 | NULL | NULL | NULL |
After applying the `WHERE` clause and selecting the listed attributes, the result will be:
| name | id |
|--------------|----|
| Document1 | 1 |
| Document2 | 3 |
b)内部JOIN
条項
SELECT documents.name, downloads.id
FROM documents
LEFT OUTER JOIN downloads
ON documents.id = downloads.document_id
AND username = 'sandeep'
For above query the intermediate join table will look like this.
| id(from documents) | name | id (from downloads) | document_id | username |
|--------------------|--------------|---------------------|-------------|----------|
| 1 | Document1 | 1 | 1 | sandeep |
| 2 | Document2 | 3 | 2 | sandeep |
| 3 | Document3 | NULL | NULL | NULL |
| 4 | Document4 | NULL | NULL | NULL |
| 5 | Document5 | NULL | NULL | NULL |
Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values.
After Selecting the listed attributes, the result will be:
| name | id |
|------------|------|
| Document1 | 1 |
| Document2 | 3 |
| Document3 | NULL |
| Document4 | NULL |
| Document5 | NULL |
intermediate join table
か?「説明」コマンドはありますか?
でINNER JOIN
それらは交換可能であり、オプティマイザはそれらを自由に再配置します。
上OUTER JOIN
の、彼らはそれが依存参加のどちら側に応じて、必ずしも互換性はありません。
読みやすさに応じて、どちらか一方に置きます。
Orders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
私のやり方は:
ON
を行う場合は、常に結合条件を句に入れてくださいINNER JOIN
。したがって、ON句にWHERE条件を追加せずに、句に入れますWHERE
。
を実行している場合は、結合の右側にあるテーブルLEFT JOIN
のON
句にWHERE条件を追加します。結合の右側を参照するWHERE句を追加すると、結合がINNER JOINに変換されるため、これは必須です。
例外は、特定のテーブルにないレコードを探す場合です。次のようにして、RIGHT JOINテーブルの一意の識別子(NULLではない)への参照をWHERE句に追加しますWHERE t2.idfield IS NULL
。したがって、結合の右側にあるテーブルを参照する必要があるのは、テーブルにないレコードを見つけるときだけです。
これは非常に一般的な質問なので、この回答は私が書いたこの記事に基づいています。
私たちは以下の持って考えるpost
とpost_comment
テーブルを:
post
次のレコードがあります。
| id | title |
|----|-----------|
| 1 | Java |
| 2 | Hibernate |
| 3 | JPA |
そして、post_comment
次の3つの行があります。
| id | review | post_id |
|----|-----------|---------|
| 1 | Good | 1 |
| 2 | Excellent | 1 |
| 3 | Awesome | 2 |
SQL JOIN句を使用すると、異なるテーブルに属する行を関連付けることができます。たとえば、CROSS JOINは、2つの結合するテーブル間の行のすべての可能な組み合わせを含むデカルト積を作成します。
CROSS JOINは特定のシナリオで役立ちますが、ほとんどの場合、特定の条件に基づいてテーブルを結合する必要があります。そして、そこがINNER JOINの出番です。
SQL INNER JOINを使用すると、ON句で指定された条件に基づいて、2つのテーブルを結合するデカルト積をフィルタリングできます。
「常に真」の条件を指定した場合、INNER JOINは結合されたレコードをフィルタリングせず、結果セットには2つの結合テーブルのデカルト積が含まれます。
たとえば、次のSQL INNER JOINクエリを実行するとします。
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1
post
とpost_comment
レコードのすべての組み合わせを取得します。
| p.id | pc.id |
|---------|------------|
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
したがって、ON句の条件が「常にtrue」の場合、INNER JOINはCROSS JOINクエリと同じです。
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id
一方、ON句の条件が「常にfalse」の場合、結合されたすべてのレコードがフィルターで除外され、結果セットは空になります。
したがって、次のSQL INNER JOINクエリを実行すると、
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id
結果は返されません。
| p.id | pc.id |
|---------|------------|
これは、上記のクエリが次のCROSS JOINクエリと同等であるためです。
SELECT
p.id AS "p.id",
pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id
最も一般的なON句の条件は、次のクエリに示すように、子テーブルの外部キー列と親テーブルの主キー列が一致する条件です。
SELECT
p.id AS "p.id",
pc.post_id AS "pc.post_id",
pc.id AS "pc.id",
p.title AS "p.title",
pc.review AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id
上記のSQL INNER JOINクエリを実行すると、次の結果セットが得られます。
| p.id | pc.post_id | pc.id | p.title | pc.review |
|---------|------------|------------|------------|-----------|
| 1 | 1 | 1 | Java | Good |
| 1 | 1 | 2 | Java | Excellent |
| 2 | 2 | 3 | Hibernate | Awesome |
したがって、ON句の条件に一致するレコードのみがクエリ結果セットに含まれます。私たちの場合、結果セットにはすべてのレコードpost
とそのpost_comment
レコードが含まれています。post
無関連した行はpost_comment
、彼らがON句の条件を満たすことができないため、除外されています。
ここでも、上記のSQL INNER JOINクエリは、次のCROSS JOINクエリと同等です。
SELECT
p.id AS "p.id",
pc.post_id AS "pc.post_id",
pc.id AS "pc.id",
p.title AS "p.title",
pc.review AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id
非ストライク行はWHERE句を満たす行であり、これらのレコードのみが結果セットに含まれます。これが、INNER JOIN句の動作を視覚化する最良の方法です。
| p.id | pc.post_id | pc.id | p.title | pc.review | | ------ | ------------ | ------- | ----------- | --------- -| | 1 | 1 | 1 | Java | 良い| | 1 | 1 | 2 | Java | 素晴らしい|| 1 | 2 | 3 | Java | 素晴らしい|| 2 | 1 | 1 | ハイバネート| 良い|| 2 | 1 | 2 | ハイバネート| 素晴らしい|| 2 | 2 | 3 | ハイバネート| 素晴らしい|| 3 | 1 | 1 | JPA | 良い|| 3 | 1 | 2 | JPA | 素晴らしい|| 3 | 2 | 3 | JPA | 素晴らしい|
INNER JOINステートメントは、INNER JOINクエリのON句で使用したのと同じ条件に一致するWHERE句を含むCROSS JOINとして書き換えることができます。
これはINNER JOINにのみ適用され、OUTER JOINには適用されません。
左結合に関しては、where句とon句には大きな違いがあります。
次に例を示します。
mysql> desc t1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| fid | int(11) | NO | | NULL | |
| v | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
テーブルt2のidがあります。
mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| v | varchar(10) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
「on句」に対するクエリ:
mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K'
-> ;
+----+-----+---+------+------+
| id | fid | v | id | v |
+----+-----+---+------+------+
| 1 | 1 | H | NULL | NULL |
| 2 | 1 | B | NULL | NULL |
| 3 | 2 | H | NULL | NULL |
| 4 | 7 | K | NULL | NULL |
| 5 | 5 | L | NULL | NULL |
+----+-----+---+------+------+
5 rows in set (0.00 sec)
「where句」に対するクエリ:
mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K';
+----+-----+---+------+------+
| id | fid | v | id | v |
+----+-----+---+------+------+
| 4 | 7 | K | NULL | NULL |
+----+-----+---+------+------+
1 row in set (0.00 sec)
行t1.v = 'K'の場合、最初のクエリがt1からのレコードと、t2からの従属行(ある場合)を返すことは明らかです。
2番目のクエリはt1から行を返しますが、t1.v = 'K'の場合のみ、それに関連付けられた行があります。
オプティマイザに関しては、結合句をONとWHEREのどちらで定義しても違いはありません。
ただし、私見では、結合を実行するときにON句を使用する方がはるかに明確だと思います。このようにして、クエリの特定のセクションで、結合の処理方法と、残りのWHERE句との混合方法を指定します。
それらのテーブルを考えてみましょう:
あ
id | SomeData
B
id | id_A | SomeOtherData
id_A
テーブルへの外部キーであること A
このクエリを書く:
SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;
この結果を提供します:
/ : part of the result
B
+---------------------------------+
A | |
+---------------------+-------+ |
|/////////////////////|///////| |
|/////////////////////|///////| |
|/////////////////////|///////| |
|/////////////////////|///////| |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+
AにはあるがBにはないということは、Bにnull値があることを意味します。
次に、の特定の部分を検討B.id_A
し、前の結果から強調表示します。
/ : part of the result
* : part of the result with the specific B.id_A
B
+---------------------------------+
A | |
+---------------------+-------+ |
|/////////////////////|///////| |
|/////////////////////|///////| |
|/////////////////////+---+///| |
|/////////////////////|***|///| |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+
このクエリを書く:
SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;
この結果を提供します:
/ : part of the result
* : part of the result with the specific B.id_A
B
+---------------------------------+
A | |
+---------------------+-------+ |
|/////////////////////| | |
|/////////////////////| | |
|/////////////////////+---+ | |
|/////////////////////|***| | |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+
これにより、内部結合の中にない値が削除されるため B.id_A = SpecificPart
次に、クエリを次のように変更します。
SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;
結果は次のとおりです。
/ : part of the result
* : part of the result with the specific B.id_A
B
+---------------------------------+
A | |
+---------------------+-------+ |
| | | |
| | | |
| +---+ | |
| |***| | |
| +---+---+-------------------------+
| |
+-----------------------------+
結果全体が、Aにあり、BにはないB.id_A = SpecificPart
パーツの削除に対してフィルターされているためB.id_A = NULL
データを結合したり、データをフィルタリングしたりしていますか?
読みやすくするために、これらのユースケースをそれぞれONとWHEREに分離することが最も理にかなっています。
JOIN条件とフィルタリング条件がWHERE句に存在するクエリを読み取るのが非常に難しくなる可能性があります。
パフォーマンスに関しては、違いはないはずですが、SQLの種類によってはクエリの計画が異なる場合があるため、試す価値があります¯\_(ツ)_/¯
(クエリの速度に影響するキャッシュに注意してください)。
また、他の人が述べたように、外部結合を使用する場合、ON句にフィルター条件を配置すると、テーブルの1つにのみ影響するため、異なる結果が得られます。
私はこれについてもっと深く投稿しました:https : //dataschool.com/learn/difference-between-where-and-on-in-sql
SQLでは、 'WHERE'句と 'ON'句は条件付きステートマントの一種ですが、それらの主な違いは、条件を指定するためにSelect / Updateステートメントで 'Where'句が使用されるのに対し、 'ON'句はテーブルが結合される前に、ターゲットテーブルとソーステーブルでレコードが一致するかどうかを検証またはチェックする結合で使用されます。
例:-'WHERE'
SELECT * FROM employee WHERE employee_id=101
例:-'ON'
2つのテーブルemployeeとemployee_detailsがあり、一致する列はemployee_idです。
SELECT * FROM employee
INNER JOIN employee_details
ON employee.employee_id = employee_details.employee_id
私があなたの質問に答えてくれれば幸いです。明確化のために元に戻します。
ジョインシーケンス効果だと思います。左上結合の場合、SQLは最初に左結合を実行し、次にwhereフィルターを実行します。下のケースでは、まずOrders.ID = 12345を見つけてから、結合を行います。
内部結合の場合WHERE
、ON
互換的に使用できます。実際、ON
相関サブクエリで使用することは可能です。例えば:
update mytable
set myscore=100
where exists (
select 1 from table1
inner join table2
on (table2.key = mytable.key)
inner join table3
on (table3.key = table2.key and table3.key = table1.key)
...
)
これは(IMHO)人間を完全に混乱させるものであり、table1
何かにリンクすることを忘れることは非常に簡単です( "driver"テーブルには "on"句がないため)が、それは合法です。
この違いは、SQLでの操作の論理的な順序によって説明するのが最も簡単だと思います。
FROM
(結合を含む)WHERE
GROUP BY
HAVING
WINDOW
SELECT
DISTINCT
UNION
、INTERSECT
、EXCEPT
ORDER BY
OFFSET
FETCH
結合は、selectステートメントの句ではなく、内の演算子ですFROM
。したがってON
、対応するJOIN
演算子に属するすべての句は、論理処理が句に到達するまでに、論理的に「すでに発生」していWHERE
ます。これは、LEFT JOIN
たとえばの場合、外部結合のセマンティクスは、WHERE
句が適用されるときまでにすでに発生していることを意味します。
このブログ投稿では、次の例について詳しく説明しています。このクエリを実行すると:
SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;
LEFT JOIN
俳優が映画でプレーしていない場合でも、そのように俳優は、フィルタリングされるので、本当に、任意の有用な効果を持っていないFILM_ID
だろうNULL
とWHERE
節は、そのような行をフィルタリングします。結果は次のようになります。
ACTOR_ID FIRST_NAME LAST_NAME COUNT
--------------------------------------
194 MERYL ALLEN 1
198 MARY KEITEL 1
30 SANDRA PECK 1
85 MINNIE ZELLWEGER 1
123 JULIANNE DENCH 1
つまり、2つのテーブルを内部結合したかのようにです。ON
句でフィルター述語を移動すると、それが外部結合の基準になります。
SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;
結果には、映画のない俳優、または映画のない俳優が含まれます FILM_ID < 10
ACTOR_ID FIRST_NAME LAST_NAME COUNT
-----------------------------------------
3 ED CHASE 0
4 JENNIFER DAVIS 0
5 JOHNNY LOLLOBRIGIDA 0
6 BETTE NICHOLSON 0
...
1 PENELOPE GUINESS 1
200 THORA TEMPLE 1
2 NICK WAHLBERG 1
198 MARY KEITEL 1
述語は常に論理的に最も意味のある場所に置いてください。
これが私の解決策です。
SELECT song_ID,songs.fullname, singers.fullname
FROM music JOIN songs ON songs.ID = music.song_ID
JOIN singers ON singers.ID = music.singer_ID
GROUP BY songs.fullname
それを機能させるには、が必要GROUP BY
です。
この助けを願っています。