web-dev-qa-db-ja.com

SQLはFROM行で複数のテーブルに対して結合を残しましたか?

ほとんどのSQL方言は、次の両方のクエリを受け入れます。

SELECT a.foo, b.foo
FROM a, b
WHERE a.x = b.x

SELECT a.foo, b.foo
FROM a
LEFT JOIN b ON a.x = b.x

外部結合が必要なときは明らかに、2番目の構文が必要になります。しかし、内部結合をするとき、なぜ私は最初の構文よりも2番目の構文を好むべきですか(またはその逆)。

240
jmucchiello

テーブルを一覧表示し、結合基準を指定するためにWHERE句を使用するという古い構文は、最近のほとんどのデータベースでは推奨されていません。

見た目だけではなく、古いクエリでは、同じクエリでINNERとOUTERの両方のジョインを使用すると、あいまいになる可能性があります。

例を挙げましょう。

システムに3つのテーブルがあるとしましょう。

Company
Department
Employee

各テーブルには、リンクされた多数の行が含まれています。あなたは複数の会社を持っていました、そして各会社は複数の部署を持つことができ、そして各部署は複数の従業員を持つことができます。

さて、今、あなたは次のことをしたいです。

すべての会社を一覧表示し、すべての部署、およびすべての従業員を含めます。部署がまだない会社もありますが、必ず含めてください。必ず従業員がいる部門のみを検索するようにしてください。ただし、必ずすべての会社をリストしてください。

だからあなたはこれを行います:

SELECT * -- for simplicity
FROM Company, Department, Employee
WHERE Company.ID *= Department.CompanyID
  AND Department.ID = Employee.DepartmentID

最後のものには内部結合があることに注意してください。これは、部署を人と一緒にしたいだけの基準を満たすためです。

わかりました、それで今何が起こりますか。問題は、データベースエンジン、クエリオプティマイザ、インデックス、およびテーブル統計に依存することです。説明させてください。

クエリオプティマイザが、最初に会社を採用し、次に部署を探し、次に従業員と内部結合することであると判断した場合、部署を持たない会社を見つけることはできません。

これは、WHERE句によって、最終的な結果に含まれるrowsが決定され、行の個々の部分ではないからです。

この場合、左側の結合のため、Department.ID列はNULLになります。したがって、INNER JOIN to Employeeになると、Employee行に対するその制約を満たす方法はないため、それは実行されません。現れる。

一方、クエリオプティマイザーが最初に部門と従業員の結合に取り組み、次に会社との左結合を行うことを決定した場合は、それらが表示されます。

そのため、古い構文はあいまいです。クエリのヒントを処理しない限り、必要なものを指定することはできません。また、データベースによってはまったく意味を持たないものもあります。

新しい構文を入力してください。これで選択できます。

たとえば、問題の説明が示すように、すべての会社が必要な場合は、これを書くことになります。

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID

ここでは、部署 - 従業員の参加を1回の参加として実行し、その後その結果を会社に残すように指定します。

さらに、名前にXという文字が含まれている部署だけが必要だとしましょう。繰り返しますが、古いスタイルの結合では、名前にXを持つ部署がない場合でも会社を失う危険性がありますが、新しい構文を使用すると、次のことができます。

SELECT *
FROM Company
     LEFT JOIN (
         Department INNER JOIN Employee ON Department.ID = Employee.DepartmentID
     ) ON Company.ID = Department.CompanyID AND Department.Name LIKE '%X%'

この追加句は結合に使用されますが、行全体に対するフィルタではありません。したがって、その行には会社情報が表示されますが、その行のすべての部門および従業員の列にNULLが含まれる可能性があります。その会社の名前にXを持つ部門がないためです。これは古い構文では難しいです。

これが、他のベンダーの中でも、MicrosoftがSQL Server 2005以降、古い外部結合構文を非推奨にし、古い内部結合構文を非推奨にした理由です。古いスタイルの外部結合構文を使用してMicrosoft SQL Server 2005または2008上で実行されているデータベースと通信する唯一の方法は、そのデータベースを8.0互換モード(別名SQL Server 2000)に設定することです。

さらに、クエリオプティマイザでたくさんのテーブルを投げることによって、たくさんのWHERE句を使用するという古い方法は、「ここにいる、できる限り最善を尽くす」と言うことに似ていました。新しい構文では、クエリオプティマイザは、どの部分が一緒になるかを理解するために行うべき作業が少なくてすみます。

それであなたはそれを持っています。

LEFT and INNER JOINは未来の波です。

JOIN構文は、条件が適用されるテーブルの近くに条件を保持します。これは、大量のテーブルを結合するときに特に便利です。

ところで、最初の構文でも外部結合をすることができます。

WHERE a.x = b.x(+)

または

WHERE a.x *= b.x

または

WHERE a.x = b.x or a.x not in (select x from b)
16
Andomar

最初の方法は古い標準です。 2番目の方法はSQL-92で導入された http://en.wikipedia.org/wiki/SQL です。完全な標準は http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt で見ることができます。

データベース会社がSQL-92標準を採用するまでに何年もかかりました。

そのため、2番目の方法が推奨される理由は、ANSIおよびISO規格委員会によるSQL規格です。

11
Dwight T

基本的に、FROM句に次のようにテーブルがリストされているとします。

SELECT * FROM
  tableA, tableB, tableC

結果は、テーブルA、B、Cのすべての行の外積です。それからWHERE tableA.id = tableB.a_idという制限を適用すると、膨大な数の行が捨てられ、さらに... AND tableB.id = tableC.b_idになり、自分が所有している行のみが得られます本当に興味があります。

DBMSは、JOINを使用してこれを記述した場合のパフォーマンスの違いが(あるとしても)無視できるように、このSQLを最適化する方法を知っています。 JOIN表記を使用すると、SQL文が読みやすくなります。more読み込み可能(IMHO、結合を使用しないと文が混乱します)。クロス積を使用するには、WHERE句に結合基準を指定する必要がありますが、それが表記法の問題です。あなたはWHERE句を次のようなものでいっぱいにしています

    tableA.id = tableB.a_id 
AND tableB.id = tableC.b_id 

これはクロス積を制限するためにのみ使用されます。 WHERE句には結果セットに対するRESTRICTIONSのみを含める必要があります。テーブル結合の基準と結果セットの制限を混在させると、あなた(そして他の人)はあなたのクエリを読みにくくなるでしょう。 JOINを確実に使用し、FROM句をFROM句に、WHERE句をWHERE句にしてください。

10
Peter Perháč

2番目の方法が推奨されるのは、where句を入れるのを忘れることによって偶然のクロスジョインが発生する可能性がはるかに低いからです。 on句を指定しないで結合すると構文チェックに失敗し、whereスタイル句を指定しないで結合すると失敗しません。クロス結合が実行されます。

また、後で左結合が必要になったときに、それらがすべて同じ構造になっていることがメンテナンスに役立ちます。そして、古い構文は1992年以来古くなっています、それを使うのをやめるのはかなり過去です。

さらに、最初の構文を排他的に使用する多くの人が結合を実際には理解しておらず、結合を理解することが照会時に正しい結果を得るために重要であることを私は発見しました。

9
HLGEM

このページには、明示的なJOINを使用した2番目の方法を採用するいくつかの理由があると思います。ただし、WHO句からJOIN条件が削除されると、WHERE句に残っている選択条件が見やすくなります。

本当に複雑なSELECT文では、何が起こっているのかを読者が理解しやすくなります。

6
Alan G

SELECT * FROM table1, table2, ...構文はいくつかのテーブルには問題ありませんが、指数関数的になると(必ずしも数学的に正確なステートメントになります)、テーブルが増えます。

JOIN構文は(最初は)書くのが難しくなりますが、どの基準がどのテーブルに影響を与えるかを明確にします。これは間違いを犯しにくくします。

また、すべての結合がINNERの場合、両方のバージョンは同等です。しかし、ステートメントのどこかにOUTER結合があると、物事ははるかに複雑になり、書いたものがあなたが書いたと思うものを照会しないことが事実上保証されます。

5
Euro Micelli

外部結合が必要なときは、2番目の構文はnot常に必要です。

Oracle:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x = b.x(+)

MSSQLServer(2000バージョンでは 廃止予定 になっていますが)/ Sybase:

SELECT a.foo, b.foo
  FROM a, b
 WHERE a.x *= b.x

しかしあなたの質問に戻りましょう。答えはわかりませんが、where句に式を追加するよりもjoinの方が自然に(少なくとも構文的には)自然であるという事実に関連する可能性があります。あなたがまさにそれをしているとき:join

2

多くの人が最初の人は理解するのが難しすぎて、それが不明であると不平を言うのを聞きます。私はそれについて問題を見ません、しかしその議論をした後、私は明快さのために内部結合でさえ第二のものを使います。

0
kemiller2002

データベースにとって、それらは同じものになってしまいます。ただし、あなたにとっては、状況によってはその2番目の構文を使用する必要があります。結局それを使用しなければならないクエリを編集するために(あなたがストレートジョインをしていたところにあなたが左ジョインを必要としていることを見いだすために)、そして一貫性のために、私は2番目の方法でパターン化するだけです。クエリを読みやすくなります。

0
Jeff Ferland

右側のテーブルに対応するレコードがない場合でも、LEFT JOINには最初のテーブルのすべてのレコードが含まれるため、最初のクエリと2番目のクエリでは結果が異なる場合があります。

0
Gavin H