SQL左結合と複数行のFROM行のテーブル?


256

ほとんどの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番目の構文を優先する必要があるのですか(またはその逆)?


1
グッファ:どうやってそれを見つけたの?私の質問は、「私はどのように」よりもベストプラクティスですが
jmucchiello

ベストプラクティスなので、これをWikiにしてください。
Binoj Antony

1
これらの2つのパフォーマンスについて誰もコメントしなかったと思います。重要な違いについて、誰かが正当なことを確認または引用できますか?
ahnbizcad 2017

@ahnbizcad与えられた2つのクエリは同じことを行いません。最初は、INNER JOIN ONと同じ結果を返します。実装はDBMSバージョン固有であり、それでも保証はほとんどありません。しかし、DBMS変換は、コンマと内部結合ON / WHEREと結合結合WHEREの場合と同等です。リレーショナルデータベースクエリの最適化/実装について学習します。
philipxy

リソースの推奨を得ましたか?巨大で密集したマニュアルが、私がここから学ぼうとする理由です。
ahnbizcad

回答:


319

テーブルを一覧表示し、WHERE句を使用して結合条件を指定するという古い構文は、ほとんどの最新のデータベースでは廃止されています。

これは単に表示するだけではなく、同じクエリでINNER結合とOUTER結合の両方を使用すると、古い構文があいまいになる可能性があります。

例を挙げましょう。

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

Company
Department
Employee

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

では、次のことを行います。

すべての会社をリストし、すべての部門とすべての従業員を含めます。一部の企業にはまだ部門がありませんが、それらも含めるようにしてください。従業員のいる部門のみを取得し、すべての会社を常にリストするようにしてください。

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

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

最後の1つには内部結合があり、部署が人のみであるという条件を満たすために注意してください。

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

クエリオプティマイザが、これを行う方法が最初に会社を選び、次に部門を見つけ、次に従業員と内部結合を行うことであると判断した場合、部門のない会社を取得することはできません。

その理由は、このWHERE句によって、行の個々の部分ではなく、最終的な結果になる行が決定されるためです。

この場合、左結合のため、Department.ID列はNULLになるため、EmployeeへのINNER JOINになると、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が付いている部署がないためです。これは古い構文では難しいです。

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

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

だからあなたはそれを持っています。

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


28
「ほとんどの最新のデータベースでは廃止されています。」---好奇心旺盛ですが、どれですか?
zerkms 2011

10
許してください、* =演算子に精通していません、それは何をしますか?ありがとう!
ultrajohn

9
Star =と= Starは(よくありました)右と左の外部結合ですか、それとも左と右ですか?年齢のために廃止されて、私は、SQL Serverの6ので、それらを使用していない
トニー・ホプキンソン

3
カンマは廃止されていません。標準でないOUTER JOIN構文*=/ =*/ *=*は非推奨です。
philipxy 2015

1
この答えは、外部結合に関するものではない質問にも答えません。コンマとINNER JOIN ONについて行う最適化についての主張の1つは誤りです。
philipxy

17

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)

2
* =構文はMS SQLServerでは非推奨であり、それには十分な理由があります。これは、読みにくくなるだけでなく、人々が考えていることを実行せず、同じように見える左結合とは異なります。(+)構文は私には馴染みのないものです。それはどのSQL実装ですか?
Euro Micelli 2009年

2
他の構文は、少なくともOracleで使用されています。
Lasse V. Karlsen、

4
SQL Server構文* =を使用しないでください。左結合ではなくクロス結合として解釈される場合があるため、一貫した結果が得られません。これはSQL Server 2000までさかのぼります。これを使用しているコードがある場合は、修正する必要があります。
HLGEM 2009年

12

最初の方法は古い規格です。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標準です。


,まだ標準です。副選択も導入さonれた場合にのみ導入する必要outer joinがありました。
philipxy 2017

12

基本的に、FROM句が次のようにテーブルをリストする場合:

SELECT * FROM
  tableA, tableB, tableC

結果はテーブルA、B、Cのすべての行のクロス積です。次にWHERE tableA.id = tableB.a_id、膨大な数の行を破棄する制限を適用し、さらに... AND tableB.id = tableC.b_idそして、本当に関心のある行のみを取得する必要がありますに。

DBMSはこのSQLを最適化する方法を知っているため、JOINを使用してこれを書き込む場合のパフォーマンスの違いは無視できます(存在する場合)。JOIN表記を使用すると、SQLステートメント読みやすくなります(結合を使用せずに、IMHOはステートメントを混乱させます)。外積を使用する場合、WHERE句に結合基準を指定する必要がありますが、これが表記上の問題です。あなたはあなたのWHERE句を次のようなもので混雑しています

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

これは、外積を制限するためにのみ使用されます。WHERE句には、結果セットへのRESTRICTIONSのみを含める必要があります。テーブルの結合条件と結果セットの制限を混在させると、クエリが読みにくくなります。必ずJOINを使用し、FROM句をFROM句に、WHERE句をWHERE句にしてください。


10

2番目の方法が推奨されるのは、where句の入力を忘れることで偶発的なクロス結合が発生する可能性がはるかに低いためです。on句のない結合は構文チェックに失敗し、where句のない古いスタイルの結合は失敗せず、クロス結合を実行します。

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

さらに、最初の構文を独占的に使用する多くの人は結合を実際に理解していないため、クエリを実行するときに正しい結果を得るには結合を理解することが重要です。


6

このページで、明示的なJOINを使用する2番目の方法を採用する理由はいくつかあると思います。ただし、JOIN基準をWHERE句から削除すると、残りの選択基準をWHERE句で確認しやすくなります。

本当に複雑なSELECTステートメントでは、読者が何が起こっているかを理解するのがはるかに簡単になります。


5

SELECT * FROM table1, table2, ...構文は、テーブルのカップルのためokですが、それは(指数関数的になるとは限らない数学的に正確な文でテーブルの数が増えると読み取ることが難しく)。

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

また、すべての結合がINNERの場合、両方のバージョンは同等です。ただし、ステートメントの任意の場所にOUTER結合があると、事態ははるかに複雑になり、あなたが書いたものがあなたが書いたと思っているものをクエリしないことが実質的に保証されます。


2

外部結合が必要な場合、2番目の構文は必ずしも必要ではありません。

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

しかし、あなたの質問に戻ります。私は答えを知らないが、それはおそらくという事実に関係している参加に式を追加するよりも(少なくとも、構文的に)より自然であるところ:あなたはまさにそれをやっている句入社します


SQLサーバーはその左結合構文を非推奨にしており、SQL Server 2000でも一貫して正しい結果が得られない場合があり(左結合の代わりにクロス結合を行う場合もあります)、SQL Serverでは使用しないでください。
HLGEM 2009年

@HLGEM:情報をありがとう。私はあなたが言っていることを反映するために私の投稿を更新します。
Pablo Santa Cruz、

0

多くの人が最初の人は理解するのが難しすぎて不明確だと不平を言うのを聞きます。問題はないと思いますが、その議論の後、わかりやすくするために、INNER JOINSでも2番目のものを使用します。


1
私はJOIN構文を使用せず、最初の方法でそれを行う習慣に育ちました。私は、私はまだで考えるのは難しいようで、私に常時結合構文をwheras、私は私の脳がそのロジックに従うように調整されていると思いますという理由だけで習慣にしばしば立ち往生しています認めなければならない。
TheTXI

3
私もそのように教えられました。コーディングスタイルを変更したのは、人々がそれを見て、何が起こっているのか簡単には認識されなかったからです。論理的な違いはなく、前者を後者よりも選択する理由が見つからないので、自分が書いたものを他の人が理解できるようにコードをより明確にすることに適応すべきだと感じました。
kemiller2002 2009年

0

データベースにとって、それらは同じになります。ただし、状況によっては、2番目の構文を使用する必要があります。最終的にそれを使用しなければならないクエリを編集するために(直線結合があった場所に左結合が必要であることがわかります)、一貫性のために、2番目の方法でのみパターン化します。クエリを読みやすくします。


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.