ほとんどの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番目の構文を優先する必要があるのですか(またはその逆)?
ほとんどの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番目の構文を優先する必要があるのですか(またはその逆)?
回答:
テーブルを一覧表示し、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は未来の波です。
OUTER 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)
最初の方法は古い規格です。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
がありました。
基本的に、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句にしてください。
2番目の方法が推奨されるのは、where句の入力を忘れることで偶発的なクロス結合が発生する可能性がはるかに低いためです。on句のない結合は構文チェックに失敗し、where句のない古いスタイルの結合は失敗せず、クロス結合を実行します。
さらに、後で左結合が必要になったときに、それらがすべて同じ構造になっているとメンテナンスに役立ちます。そして、古い構文は1992年以来古くなっており、それを使用するのをやめるのはかなり過去のことです。
さらに、最初の構文を独占的に使用する多くの人は結合を実際に理解していないため、クエリを実行するときに正しい結果を得るには結合を理解することが重要です。
SELECT * FROM table1, table2, ...
構文は、テーブルのカップルのためokですが、それは(指数関数的になるとは限らない数学的に正確な文でテーブルの数が増えると読み取ることが難しく)。
JOIN構文は(最初は)書くのが難しいですが、どの基準がどのテーブルに影響を与えるかを明示します。これは間違いをすることをはるかに難しくします。
また、すべての結合がINNERの場合、両方のバージョンは同等です。ただし、ステートメントの任意の場所にOUTER結合があると、事態ははるかに複雑になり、あなたが書いたものがあなたが書いたと思っているものをクエリしないことが実質的に保証されます。
外部結合が必要な場合、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
しかし、あなたの質問に戻ります。私は答えを知らないが、それはおそらくという事実に関係している参加に式を追加するよりも(少なくとも、構文的に)より自然であるところ:あなたはまさにそれをやっている句入社します。
多くの人が最初の人は理解するのが難しすぎて不明確だと不平を言うのを聞きます。問題はないと思いますが、その議論の後、わかりやすくするために、INNER JOINSでも2番目のものを使用します。
データベースにとって、それらは同じになります。ただし、状況によっては、2番目の構文を使用する必要があります。最終的にそれを使用しなければならないクエリを編集するために(直線結合があった場所に左結合が必要であることがわかります)、一貫性のために、2番目の方法でのみパターン化します。クエリを読みやすくします。