テーブル A とテーブル B 間の完全な結合 SQL ステートメントを表すベン図。

構造化問い合わせ言語(SQL)の結合句は、1つまたは複数のテーブルの列を新しいテーブルに結合しますこの操作関係代数における結合操作に相当します非公式には、結合は2つのテーブルをつなぎ合わせ、一致するフィールドを持つレコードを同じ行に置きます。結合句には、、、、、、など、いくつかのバリエーションありますJOININNERLEFT OUTERRIGHT OUTERFULL OUTERCROSS

例の表

[編集]

結合タイプを説明するために、この記事の残りの部分では次の表を使用します。

従業員テーブル
苗字部門ID
ラファティ31
ジョーンズ33
ハイゼンベルク33
ロビンソン34
スミス34
ウィリアムズNULL
部門テーブル
部門ID部門名
31販売
33エンジニアリング
34事務員
35マーケティング

Department.DepartmentIDはテーブルの主キーですDepartmentが、 は外部キーEmployee.DepartmentIDです

ではEmployee、「Williams」はまだ部門に割り当てられていないことに注意してください。また、「Marketing」部門には従業員が割り当てられていません。

上記のテーブルを作成するための SQL ステートメントは次のとおりです。

テーブル部門を作成   DepartmentID INTキーNOT NULL ,      部門名VARCHAR ( 20 ) );従業員テーブルの作成    VARCHAR ( 20 ),  DepartmentID INT参照部門( DepartmentID )   );部門挿入  VALUES ( 31 , '売上' ),   33 「エンジニアリング」)、  34歳「聖職者」)、  35 「マーケティング」 従業員挿入  「ラファティ」31 )、   「ジョーンズ」33 )、  『ハイゼンベルク』33 )、  『ロビンソン』34 )、  「スミス」34 )、  ( 'ウィリアムズ' , NULL ); 

クロス結合

[編集]

CROSS JOIN結合されたテーブルの行の直積を返します。言い換えれば、最初のテーブルの各行と2番目のテーブルの各行を結合した行を生成します。[ 1 ]

従業員.姓従業員.部門ID部門.部署名部門.部門ID
ラファティ31販売31
ジョーンズ33販売31
ハイゼンベルク33販売31
スミス34販売31
ロビンソン34販売31
ウィリアムズNULL販売31
ラファティ31エンジニアリング33
ジョーンズ33エンジニアリング33
ハイゼンベルク33エンジニアリング33
スミス34エンジニアリング33
ロビンソン34エンジニアリング33
ウィリアムズNULLエンジニアリング33
ラファティ31事務員34
ジョーンズ33事務員34
ハイゼンベルク33事務員34
スミス34事務員34
ロビンソン34事務員34
ウィリアムズNULL事務員34
ラファティ31マーケティング35
ジョーンズ33マーケティング35
ハイゼンベルク33マーケティング35
スミス34マーケティング35
ロビンソン34マーケティング35
ウィリアムズNULLマーケティング35

明示的なクロス結合の例:

SELECT * FROM従業員CROSS JOIN部門;     

暗黙的なクロス結合の例:

従業員部門から*を選択;   

クロス結合は、常に真となる条件を持つ内部結合に置き換えることができます。

SELECT * FROM従業員INNER JOIN部門ON 1 = 1 ;       

CROSS JOINそれ自体は、結合されたテーブルから行をフィルタリングするための述語を適用しません。a の結果はCROSS JOINa 句を使用してフィルタリングすることができWHERE、その結果、内部結合と同等の結果が生成される場合があります。

SQL:2011標準では、クロス結合はオプションの F401「拡張結合テーブル」パッケージの一部です。

通常の使用目的は、サーバーのパフォーマンスを確認することです。[なぜ? ]

内部結合

[編集]

内部結合(または結合)では、結合された 2 つのテーブルの各行の列値が一致している必要があります。これはアプリケーションでよく使用される結合操作ですが、すべての状況で最適な選択肢であるとは限りません。内部結合は、結合述語に基づいて 2 つのテーブル(A と B)の列値を組み合わせることで、新しい結果テーブルを作成します。クエリは、A の各行を B の各行と比較し、結合述語を満たすすべての行のペアを検索します。結合述語が NULL 以外のの一致によって満たされると、A と B の一致した行の各ペアの列値が結果行に結合されます。

結合の結果は、まずテーブル内のすべての行の直積(またはクロス結合)(テーブルAのすべての行とテーブルBのすべての行を結合)を計算し、次に結合述語を満たすすべての行を返すことで定義できます。実際のSQL実装では、直積の計算は遅く、保存に膨大な量のメモリが必要になることが多いため、ハッシュ結合ソートマージ結合などの他の手法が一般的に使用されます。

SQLでは、結合を表現するための2つの異なる構文、「明示的結合記法」と「暗黙的結合記法」が規定されています。「暗黙的結合記法」はもはやベストプラクティスとはみなされていません誰がベストプラクティスと呼ぶのでしょうか?が、データベースシステムでは依然としてサポートされています。

「明示的な結合表記法」では、次の例のように、JOINキーワード (オプションでINNERキーワードを前に付けた ) を使用して結合するテーブルを指定し、ONキーワードを使用して結合の述語を指定します。

SELECT employee.LastName , employee.DepartmentID , department.DepartmentName FROM employee INNER JOIN department ON employee.DepartmentID = department.DepartmentID ;           
従業員.姓従業員.部門ID部門.部署名
ロビンソン34事務員
ジョーンズ33エンジニアリング
スミス34事務員
ハイゼンベルク33エンジニアリング
ラファティ31販売

FROM「暗黙的な結合記法」は、文の節において、結合するテーブルをSELECTカンマで区切って列挙するだけです。したがって、これはクロス結合を指定し、このWHERE節では追加のフィルタ述語(明示的な記法の結合述語と同等の機能を持つ)を適用できます。

次の例は前の例と同じですが、今回は暗黙的な結合表記を使用しています。

SELECT employee.LastName , employee.DepartmentID , department.DepartmentName FROM employee , department WHERE employee.DepartmentID = department.DepartmentID ;         

上記の例で示したクエリは、Employeeテーブルとdepartmentテーブルを、両方のテーブルのDepartmentID列を使用して結合します。これらのテーブルのDepartmentIDが一致する場合(つまり、結合述語が満たされる場合)、クエリは2つのテーブルのLastNameDepartmentID、およびDepartmentName列を1つの結果行に結合します。DepartmentIDが一致しない場合は、結果行は生成されません。

したがって、上記のクエリの実行結果は次のようになります。

従業員.姓従業員.部門ID部門.部署名
ロビンソン34事務員
ジョーンズ33エンジニアリング
スミス34事務員
ハイゼンベルク33エンジニアリング
ラファティ31販売

従業員「ウィリアムズ」と部門「マーケティング」は、クエリ実行結果に表示されません。どちらのテーブルにも、対応する行が存在しません。「ウィリアムズ」には関連する部門がなく、部門ID 35(「マーケティング」)を持つ従業員もいません。目的の結果によっては、この動作は微妙なバグである可能性があり、内部結合を外部結合に置き換えることで回避できます。

内部結合とNULL値

[編集]

NULL値を含む可能性のある列でテーブルを結合する際には、プログラマーは特別な注意を払う必要があります。結合条件で、結合列がNULL値であることを最初に確認しNOT NULLてから残りの述語条件を適用するような組み合わせ述語を明示的に使用しない限り、NULLは他の値(NULL自身でさえも)と一致することはないからです。内部結合は、参照整合性を強制するデータベース、または結合列がNULL値ではないことが保証されているデータベースでのみ安全に使用できます。多くのトランザクション処理リレーショナルデータベースは、データ整合性を確保するために原子性、一貫性、独立性、永続性(ACID)データ更新標準に依存しているため、内部結合は適切な選択肢となります。しかし、トランザクションデータベースには通常、NULL値が許可される望ましい結合列も存在します。多くのレポート処理リレーショナルデータベースとデータウェアハウスは、大量の抽出、変換、ロード(ETL)バッチ更新を使用します。これらのバッチ更新は参照整合性の強制を困難または不可能にし、SQLクエリ作成者が変更できない潜在的にNULL値の結合列を生み出し、内部結合によってエラーが示されないままデータが省略される原因となります。内部結合を使用するかどうかは、データベースの設計とデータ特性によって異なります。 1 つのテーブル内の結合列に NULL 値が含まれる可能性がある場合は、通常、内部結合の代わりに左外部結合を使用できます。

NULL (空) になる可能性のあるデータ列は、NULL 値の行を削除することが目的である場合を除いて、内部結合のリンクとして使用しないでください。 NULL 結合列を結果セットから意図的に削除する場合、テーブル結合とフィルタリングが 1 つのステップで行われるため、内部結合の方が外部結合より高速になることがあります。 逆に、内部結合は、SQL Where 句のデータベース関数と組み合わせて大規模なクエリで使用すると、パフォーマンスがひどく低下したり、サーバーがクラッシュしたりする可能性があります。 [ 2 ] [ 3 ] [ 4 ]、SQL Where 句の関数によって、データベースが比較的コンパクトなテーブル インデックスを無視することがあります。データベースは、計算値に依存するフィルターを使用して行数を減らす前に、両方のテーブルから選択された列を読み取って内部結合することがあり、その結果、比較的膨大な量の非効率的な処理が発生します。

数値識別コードの全文記述を参照するマスターテーブル(ルックアップテーブル)を含む複数のテーブルを結合して結果セットを生成する場合、外部キーのいずれかにNULL値が含まれていると、エラーが表示されずに行全体が結果セットから削除される可能性があります。1つ以上の内部結合と複数の外部結合を含む複雑なSQLクエリでも、内部結合リンク列にNULL値が含まれるリスクは同じです。

内部結合を含む SQL コードへのコミットメントは、ベンダーの更新、設計の変更、およびデータの変換、移行、一括インポート、マージなどのアプリケーションのデータ検証ルール外での一括処理など、将来の変更によって NULL 結合列が導入されないことを前提としています。

内部結合は、さらに等結合、自然結合、またはクロス結合に分類できます。

等結合

[編集]

等価結合(equy-join)は「唯一有効な演算」とも呼ばれ、結合述語において等価<比較のみを使用する比較演算子ベースの結合の一種です。他の比較演算子(など)を使用すると、結合は等価結合として不適格となります。上記のクエリは、既に等価結合の例を示しています。

SELECT * FROM employee JOIN department ON employee.DepartmentID = department.DepartmentID ;        

等価結合は以下のように記述できます。

SELECT * FROM employee , department WHERE employee.DepartmentID = department.DepartmentID ;      

等価結合の列が同じ名前を持つ場合、SQL-92では等価結合を表現するための省略可能な表記法として次のUSING構文が用意されています: [ 5 ]

SELECT * FROM employee INNER JOIN department USING ( DepartmentID ) ;       

しかし、このUSING構文は単なる構文糖ではありません。結果セットは、明示的な述語を持つバージョンの結果セットとは異なります。具体的には、USINGリストに記述されている列は、結合内の各テーブルごとに1回ではなく、修飾されていない名前で1回だけ出現します。上記の例では、DepartmentID列は1つだけで、 またはemployee.DepartmentIDは存在しませんdepartment.DepartmentID

このUSING句は、MS SQL Server および Sybase ではサポートされていません。

自然結合

[編集]

自然結合は等結合の特殊なケースです。自然結合(⋈)は二項演算子で、( R⋈S )と表記されます。ここで、RSは関係です[ 6 ]自然結合の結果は、 RSに含まれる、共通の属性名が等しいタプルのすべての組み合わせの集合です。例として、 EmployeeテーブルDeptテーブルとその自然結合を考えてみましょう。

従業員
名前従業員ID部署名
ハリー3415ファイナンス
サリー2241販売
ジョージ3401ファイナンス
ハリエット2202販売
部門
部署名マネージャー
ファイナンスジョージ
販売ハリエット
生産チャールズ
従業員 部門 
名前従業員ID部署名マネージャー
ハリー3415ファイナンスジョージ
サリー2241販売ハリエット
ジョージ3401ファイナンスジョージ
ハリエット2202販売ハリエット

これは関係の合成を定義するためにも使用できます。例えば、EmployeeDeptの合成は、上記に示したように、共通属性DeptNameを除くすべての属性に投影された結合です。圏論では、この結合はまさにファイバー積です。

自然結合は、論理 AND の関係版であるため、最も重要な演算子の 1 つと言えるでしょう。AND で接続された 2 つの述語のそれぞれに同じ変数が出現する場合、その変数は同じものを表し、両方とも常に同じ値に置き換えられる必要があることに注意してください。特に、自然結合では、外部キーによって関連付けられた関係の組み合わせが可能です。たとえば、上記の例では、外部キーはおそらくEmployee . DeptNameからDept . DeptNameを保持しており、 EmployeeDeptの自然結合によってすべての従業員とその部署が結合されています。これが機能するのは、外部キーが同じ名前の属性間を保持しているためです。Dept . managerからEmployee . Nameへの外部キーのようにそうでない場合は、自然結合を行う前にこれらの列の名前を変更する必要があります。このような結合は、等価結合と呼ばれることもあります。

より正式には、自然結合のセマンティクスは次のように定義されます。

ここで、Funは、関係r関数である場合にのみ真となる述語です。通常、 RSは少なくとも1つの共通属性を持つ必要がありますが、この制約が省略され、RSに共通属性がない場合、自然な結合はまさに直積になります。

自然結合は、コッドのプリミティブを用いて以下のようにシミュレートできる。c 1 , ..., c mをR共通する属性名、 S , r 1 , ..., r nをRに固有の属性名s 1 , ..., skSに固有の属性名とする。さらに、属性名 x 1 , ..., x mはRにもSにも存在しないとする。まず、Sに共通する属性名を以下のように変更する。

次に、デカルト積を取り、結合するタプルを選択します。

自然結合は、結合先のテーブルで同じ列名を持つ両方のテーブルのすべての列を比較することで、暗黙的に結合述語が生成される等価結合の一種です。結合後のテーブルには、同じ名前の列のペアごとに1つの列のみが含まれます。同じ名前の列が見つからない場合、結果はクロス結合となります。

ほとんどの専門家は、自然結合は危険であり、そのため使用を強く推奨していないことに同意しています。[ 7 ]危険は、他のテーブルの別の列と同じ名前の新しい列を不用意に追加することにあります。既存の自然結合は、その新しい列を「自然に」比較に使用し、以前とは異なる基準(異なる列から)を使用して比較/照合を行う可能性があります。そのため、テーブル内のデータは変更されておらず、拡張されているだけであるにもかかわらず、既存のクエリが異なる結果を生成する可能性があります。列名を使用してテーブルリンクを自動的に決定することは、数百または数千のテーブルを持つ大規模なデータベースでは選択肢ではなく、命名規則に非現実的な制約を課すことになります。実際のデータベースは、ビジネスルールやコンテキストにより、外部キーデータが一貫して入力されていない(NULL値が許容される)ように設計されるのが一般的です。異なるテーブル内の類似データの列名を変更することは一般的な慣行であり、この厳格な一貫性の欠如により、自然結合は議論のための理論的な概念に追いやられています。

上記の内部結合のサンプルクエリは、次のように自然結合として表現できます。

SELECT * FROM従業員NATURAL JOIN部門;     

明示的なUSING句と同様に、結合されたテーブルには修飾子のない DepartmentID 列が 1 つだけ存在します。

部門ID従業員.姓部門.部署名
34スミス事務員
33ジョーンズエンジニアリング
34ロビンソン事務員
33ハイゼンベルクエンジニアリング
31ラファティ販売

PostgreSQL、MySQL、Oracleは自然結合をサポートしていますが、Microsoft T-SQLとIBM DB2はサポートしていません。結合に使用される列は暗黙的であるため、結合コードではどの列が期待されるかが示されず、列名の変更によって結果が変わる可能性があります。SQL :2011標準では、自然結合はオプションのF401「拡張結合テーブル」パッケージの一部です。

多くのデータベース環境では、列名はクエリ開発者ではなく外部ベンダーによって管理されています。自然結合では、列名の安定性と一貫性が前提とされていますが、ベンダーが義務付けているバージョンアップの際に列名が変更される可能性もあります。

外部結合

[編集]

結合されたテーブルは、一致する行が他に存在しない場合でも、各行を保持します。外部結合は、保持されるテーブルの行(左、右、または両方)に応じて、左外部結合、右外部結合、および完全外部結合にさらに分類されます(この場合、右はキーワードの両側を指しますJOIN)。内部結合と同様に、すべての種類の外部結合は、等結合自然結合θ結合)など、さらにサブカテゴリに分類できます。[ 8 ]ON <predicate>

標準 SQL には、外部結合の暗黙的な結合表記は存在しません。

左側の円と重なり合う部分が塗りつぶされたベン図。
テーブル A とテーブル B 間の左結合 SQL ステートメントを表すベン図。

左外部結合

[編集]

テーブルAとBの左外部結合(または単に左結合)の結果には、結合条件で「右」テーブル(B)に一致する行が見つからない場合でも、常に「左」テーブル(A)のすべての行が含まれます。つまり、句がONBの特定の行に一致する行を0行とした場合(Aの特定の行に対して)、結合は結果に行(その行に対して)を返しますが、Bの各列にはNULLが含まれます。左外部結合は、内部結合のすべての値に加えて、左テーブルで右テーブルと一致しないすべての値(リンク列にNULL(空)値を持つ行を含む)を返します。

たとえば、これにより従業員の部署を見つけることができますが、部署に割り当てられていない従業員も表示されます (割り当てられていない従業員が結果から除外された上記の内部結合の例とは対照的です)。

左外部結合の例(OUTERキーワードはオプション)。追加の結果行(内部結合と比較)はイタリック体で表示されます。

SELECT * FROM employee LEFT OUTER JOIN department ON employee . DepartmentID = department . DepartmentID ;          
従業員.姓従業員.部門ID部門.部署名部門.部門ID
ジョーンズ33エンジニアリング33
ラファティ31販売31
ロビンソン34事務員34
スミス34事務員34
ウィリアムズNULLNULLNULL
ハイゼンベルク33エンジニアリング33

代替構文

[編集]

Oracleは非推奨の[ 9 ]構文をサポートしています。

SELECT * FROM従業員,部門WHERE従業員.部門ID =部門.部門ID ( + )      

Sybase は次の構文をサポートしています ( Microsoft SQL Server ではバージョン 2000 以降この構文は非推奨です)。

SELECT * FROM employee , department WHERE employee.DepartmentID * = department.DepartmentID      

IBM Informix は次の構文をサポートしています。

SELECT * FROM employee , OUTER department WHERE employee.DepartmentID = department.DepartmentID       
ベン図では、正しい円と重なり合う部分が塗りつぶされて表示されます。
テーブル A とテーブル B 間の正しい結合 SQL ステートメントを表すベン図。

右外部結合

[編集]

右外部結合(または右結合)は、テーブルの扱いが逆であることを除いて、左外部結合とほぼ同じです。「右」テーブル(B)のすべての行は、結合後のテーブルに少なくとも1回出現します。「左」テーブル(A)に一致する行が存在しない場合、Bに一致しない行については、Aの列にNULLが出現します。

右外部結合は、右テーブルのすべての値と、左テーブルで一致する値を返します(一致する結合述語がない場合はNULL)。例えば、これにより、各従業員とその所属部署を検索できるだけでなく、従業員がいない部署も表示できます。

以下は右外部結合の例です (OUTERキーワードはオプション)。追加の結果行は斜体で示されています。

SELECT * FROM employee RIGHT OUTER JOIN department ON employee . DepartmentID = department . DepartmentID ;          
従業員.姓従業員.部門ID部門.部署名部門.部門ID
スミス34事務員34
ジョーンズ33エンジニアリング33
ロビンソン34事務員34
ハイゼンベルク33エンジニアリング33
ラファティ31販売31
NULLNULLマーケティング35

右外部結合と左外部結合は機能的に同等です。どちらにも、他方が提供できない機能はありません。そのため、テーブルの順序を入れ替える限り、右外部結合と左外部結合は互いに置き換えることができます。

右の円、左の円、および重なり合う部分が塗りつぶされたベン図。
テーブル A とテーブル B 間の完全な結合 SQL ステートメントを表すベン図。

完全外部結合

[編集]

概念的には、完全外部結合は左外部結合と右外部結合の両方の効果を組み合わせたものです。完全外部結合されたテーブルの行が一致しない場合、結果セットでは、一致する行がないテーブルのすべての列にNULL値が含まれます。一致する行については、結果セットに1行(両方のテーブルから取得した列を含む)が生成されます。

たとえば、これにより、部門に所属する各従業員と従業員がいる各部門を確認できるだけでなく、部門に属していない各従業員と従業員がいない各部門も確認できます。

完全外部結合の例(OUTERキーワードはオプションです):

SELECT * FROM employee FULL OUTER JOIN department ON employee . DepartmentID = department . DepartmentID ;          
従業員.姓従業員.部門ID部門.部署名部門.部門ID
スミス34事務員34
ジョーンズ33エンジニアリング33
ロビンソン34事務員34
ウィリアムズNULLNULLNULL
ハイゼンベルク33エンジニアリング33
ラファティ31販売31
NULLNULLマーケティング35

一部のデータベースシステムは外部結合機能を完全に直接サポートしていませんが、内部結合と、左側のテーブルと右側のテーブルのそれぞれから「単一テーブル行」に対するUNION ALL選択を使用することで、外部結合をエミュレートできます。同じ例は次のように表すことができます。

SELECT employee.LastName employee.DepartmentID department.DepartmentName department.DepartmentID FROM employee INNER JOIN department ON employee.DepartmentID = department.DepartmentID           ユニオンオール SELECT employee.LastName , employee.DepartmentID , cast ( NULL as varchar ( 20 ) ) , cast ( NULL as integer ) FROM employee WHERE NOT EXISTS ( SELECT * FROM department WHERE employee.DepartmentID = department.DepartmentID )                    ユニオンオール SELECT cast ( NULL as varchar ( 20 )), cast ( NULL as integer ), department . DepartmentName , department . DepartmentID FROM department WHERE NOT EXISTS ( SELECT * FROM employee WHERE employee . DepartmentID = department . DepartmentID )                    

別の方法としては、左外部結合と右外部結合の UNION ALL から MINUS 内部結合を求める方法があります。

自己結合

[編集]

自己結合とは、テーブルをそれ自身に結合することである。[ 10 ]

[編集]

従業員用のテーブルが2つあり、最初のテーブルと2番目のテーブルの従業員が同じ国籍を持つ従業員を検索するクエリを実行した場合、通常の結合操作で目的のテーブルを見つけることができます。しかし、従業員情報はすべて1つの大きなテーブルに含まれています。[ 11 ]

Employee次のような変更されたテーブルを検討してください。

従業員テーブル
従業員ID苗字部門ID
123ラファティオーストラリア31
124ジョーンズオーストラリア33
145ハイゼンベルクオーストラリア33
201ロビンソンアメリカ合衆国34
305スミスドイツ34
306ウィリアムズドイツNULL

ソリューションクエリの例は次のようになります。

SELECT F.EmployeeID F.LastName S.EmployeeID S.LastName F.Country FROM Employee F INNER JOIN Employee S ON F.Country = S.Country WHERE F.EmployeeID < S.EmployeeID ORDER BY F.EmployeeID S.EmployeeID ;                     

その結果、次の表が生成されます。

国別に自己結合した従業員テーブル
従業員ID苗字従業員ID苗字
123ラファティ124ジョーンズオーストラリア
123ラファティ145ハイゼンベルクオーストラリア
124ジョーンズ145ハイゼンベルクオーストラリア
305スミス306ウィリアムズドイツ

この例では、次のようになります。

  • Fこれらは、従業員テーブルの最初のコピーと 2 番目のコピーの別名Sです。
  • この条件では、F.Country = S.Country異なる国の従業員同士のペアは除外されます。サンプルの質問では、同じ国の従業員同士のペアのみを求めていました。
  • この条件は、最初の従業員の が2番目の従業員の 以上のF.EmployeeID < S.EmployeeIDペアリングを除外します。言い換えれば、この条件の効果は、重複したペアリングと自己ペアリングを除外することです。この条件がない場合、以下のようなあまり有用でない表が生成されます(以下の表は結果の「ドイツ」部分のみを示しています)。EmployeeIDEmployeeID
従業員ID苗字従業員ID苗字
305スミス305スミスドイツ
305スミス306ウィリアムズドイツ
306ウィリアムズ305スミスドイツ
306ウィリアムズ306ウィリアムズドイツ

元の質問を満たすには、中央の 2 つのペアのうち 1 つだけが必要であり、この例では最上部と最下部はまったく重要ではありません。

代替案

[編集]

外部結合の効果は、INNER JOINと、結合条件を満たさない「メイン」テーブルの行のSELECT文との間にUNION ALL文を使用することで実現できます。例えば、

SELECT employee.LastName , employee.DepartmentID , department.DepartmentName FROM employee LEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID ;           

次のようにも書ける。

SELECT employee.LastName , employee.DepartmentID , department.DepartmentName FROM employee INNER JOIN department ON employee.DepartmentID = department.DepartmentID          ユニオンオール SELECT employee.LastName , employee.DepartmentID , cast ( NULL as varchar ( 20 ) ) FROM employee WHERE NOT EXISTS ( SELECT * FROM department WHERE employee.DepartmentID = department.DepartmentID )                 

実装

[編集]
三角形クエリ R(A, B) ⋈ S(B, C) ⋈ T(A, C) の、バイナリ結合を用いたクエリプラン。まず S と T を結合し、その結果を R と結合します。
三角形クエリ R(A, B) ⋈ S(B, C) ⋈ T(A, C) の、バイナリ結合を使用するクエリプラン。まず R と S を結合し、その結果を T と結合します。
三角形クエリR(A, B) ⋈ S(B, C) ⋈ T(A, C)2つの可能なクエリプラン。1つ目はST を最初に結合し、その結果をRと結合します。2つ目はRS を最初に結合し、その結果をTと結合します。

データベースシステムにおける多くの研究は、結合の効率的な実装を目指してきました。これは、リレーショナルシステムでは一般的に結合が求められるものの、その効率的な実行を最適化することが困難であるためです。この問題は、内部結合が可換的かつ連想的に動作するために発生します。実際には、ユーザーは結合するテーブルのリストと使用する結合条件を指定するだけでよく、データベースシステムが操作を実行する最も効率的な方法を決定する必要があります。クエリに関係するテーブルの数が増えるにつれて、選択はより複雑になります。各テーブルは、レコード数、平均レコード長(NULLフィールドを考慮)、および使用可能なインデックスにおいて異なる特性を持っています。WHERE句フィルターも、クエリの量とコストに大きな影響を与える可能性があります。

クエリオプティマイザは、結合を含むクエリの実行方法を決定します。クエリオプティマイザには、2つの基本的な自由度があります。

  1. 結合順序:関数は可換的かつ連想的に結合されるため、システムがテーブルを結合する順序はクエリの最終的な結果セットに影響を与えません。ただし、結合順序は結合操作のコストに大きな影響を与える可能性があるため、最適な結合順序を選択することが非常に重要になります。
  2. 結合方法:2つのテーブルと結合条件が与えられた場合、複数のアルゴリズムで結合結果セットを生成できます。どのアルゴリズムが最も効率的に実行されるかは、入力テーブルのサイズ、各テーブルから結合条件に一致する行数、およびクエリの残りの部分で必要な操作によって異なります。

多くの結合アルゴリズムは、入力を異なる方法で扱います。結合への入力は、それぞれ「外側」および「内側」の結合オペランド、あるいは「左」および「右」と呼ばれます。例えば、ネストされたループの場合、データベースシステムは外側のリレーションの各行について、内側のリレーション全体をスキャンします。

結合を含むクエリプランは次のように分類できる。[ 12 ]

左ディープ
プラン内の各結合の内部オペランドとして、別の結合ではなくベーステーブルを使用する
右深
プラン内の各結合の外部オペランドとして基本テーブルを使用する
ふさふさした
左深でも右深でもない。結合への入力は両方とも結合の結果である可能性がある。

これらの名前は、クエリ プランをツリーとして描画した場合の外観に由来しており、左側に外部結合関係、右側に内部関係があります (慣例に従って)。

結合アルゴリズム

[編集]
結合アルゴリズムの特性の図解。2つ以上の属性を持つ2つ以上のリレーション間の結合を実行する場合、ハッシュ結合などのバイナリ結合アルゴリズムは一度に2つのリレーションを操作し、結合条件内のすべての属性を結合します。一方、ジェネリック結合などの最悪のケースに最適なアルゴリズムは、一度に1つの属性を操作しますが、その属性を持つすべてのリレーションを結合します。[ 13 ]

バイナリ結合操作を実行するための基本的なアルゴリズムは3つあります。ネストループ結合ソートマージ結合ハッシュ結合です。最悪のケースでも、最適な結合アルゴリズムは、2つ以上のリレーション間の結合において、バイナリ結合アルゴリズムよりも漸近的に高速です

結合インデックス

[編集]

結合インデックスは、データウェアハウスでの結合クエリの処理を容易にするデータベースインデックスです。現在(2012年)では、 Oracle [ 14 ]Teradata [ 15 ]による実装で利用可能です

Teradata実装では、1つ以上のテーブルから指定された列、列の集計関数、または日付列の構成要素を、データベースビューの定義に類似した構文で指定します。1つの結合インデックスには、最大64個の列/列式を指定できます。オプションで、複合データの主キーを定義する列も指定できます。並列ハードウェアでは、これらの列値を使用してインデックスの内容を複数のディスクに分割します。ユーザーがソーステーブルを対話的に更新すると、結合インデックスの内容も自動的に更新されます。WHERE句で結合インデックスで定義されている列または列式の完全なサブセットの組み合わせを指定するクエリ(いわゆる「カバーリングクエリ」)では、クエリ実行時に元のテーブルとそのインデックスではなく、結合インデックスが参照されます。

Oracle実装では、ビットマップインデックスの使用に限定されています。ビットマップ結合インデックスは、低カーディナリティ列(Oracleドキュメントによると、300個未満の異なる値を含む列)に使用され、複数の関連テーブルの低カーディナリティ列を結合します。Oracleが使用する例は、異なるサプライヤーが異なる部品を提供する在庫システムです。スキーマには3つのリンクテーブルがあります。2つの「マスターテーブル」(PartとSupplier)と1つの「詳細テーブル」(Inventory)です。最後のテーブルは、SupplierとPartをリンクする多対多テーブルで、最も多くの行を含んでいます。すべての部品にはPart Typeがあり、すべてのサプライヤーは米国に拠点を置いており、State列を持っています。米国には60を超える州と地域はなく、Part Typeは300を超えることはありません。ビットマップ結合インデックスは、上記の3つのテーブルに対する標準的な3テーブル結合を使用して定義され、インデックスにはPart_Type列とSupplier_State列を指定します。ただし、列 Part_Type と Supplier_State はそれぞれ Supplier と Part から「借用」されているにもかかわらず、Inventory テーブルで定義されています。

Teradata の場合、Oracle ビットマップ結合インデックスは、クエリの WHERE 句で結合インデックスに含まれる列に限定して指定されている場合にのみ、クエリに応答するために利用されます。

ストレートジョイント

[編集]

一部のデータベースシステムでは、結合においてテーブルを特定の順序で読み込むよう強制することができます。これは、結合オプティマイザが非効率的な順序でテーブルを読み込むことを選択した場合に使用されます。例えばMySQLでは、このコマンドはSTRAIGHT_JOINクエリに記述された順序通りにテーブルを読み込みます。[ 16 ]

参照

[編集]

参考文献

[編集]

引用

[編集]
  1. ^ SQL クロス結合
  2. ^ Robidoux, Greg (2007-05-03). 「パフォーマンス向上のため、WHERE句でSQL Server関数の使用を避ける」 . MSSQL Tips.
  3. ^ Wolf, Patrick (2006年11月30日). 「Oracle APEXの内部情報「SQL文でPL/SQL関数を使用する場合の注意点」」 Oracle APEXの内部情報。 2018年12月27日時点のオリジナルよりアーカイブ。
  4. ^ Larsen, Gregory A. (2009年10月29日). 「T-SQLベストプラクティス - 列リストやWHERE句でスカラー値関数を使用しない」 . データベースジャーナル.
  5. ^ USINGキーワードによる結合の簡素化
  6. ^ Unicodeでは、蝶ネクタイの記号は ⋈ (U+22C8) です。
  7. ^ Tomに聞く「OracleのANSI結合サポート」 基本に立ち返る:内部結合 » Eddie Awadのブログ 2010年11月19日アーカイブWayback Machine
  8. ^ Silberschatz, Abraham ; Korth, Hank ; Sudarshan, S. (2002). 「セクション4.10.2: 結合の種類と条件」.データベースシステムコンセプト(第4版). McGraw-Hill. p. 166. ISBN 0072283637
  9. ^ Oracle 左外部結合
  10. ^ シャー 2005、165ページ
  11. ^ Pratt 2005、pp. 115–6より改変
  12. ^ Yu & Meng 1998、p. 213
  13. ^ Wang, Yisu Remy; Willsey, Max; Suciu, Dan (2023-01-27). 「フリー結合:最悪ケースの最適結合と従来の結合の統合」. arXiv : 2301.10841 [ cs.DB ].
  14. ^ Oracleビットマップ結合インデックス。「データベースの概念 - 5 インデックスと索引構成表 - ビットマップ結合インデックス」 。 2024年6月23日閲覧
  15. ^ Teradata Join Indexes.「SQLデータ定義言語の構文と例 - CREATE JOIN INDEX」 . 2024年6月23日閲覧
  16. ^ 「13.2.9.2 JOIN構文」 . MySQL 5.7リファレンスマニュアル. Oracle Corporation . 2015年12月3日閲覧

出典

[編集]
[編集]