SQLアタマアカデミー

第10回 結合大全 (5)非等値結合

この記事を読むのに必要な時間:およそ 2 分

非等値結合

自己結合の用途

ところで,この自己結合というのは,いったいどういう局面で使う結合なのでしょう。これも業務によってはあまり利用しない人も多いかもしれません。

実は,自己結合というのは,SQLにおいてはほぼ用途が決まっています。それは,⁠行間比較」をしたい場合です。行間比較とは,たとえばランキング(順位)算出のように行をまたいで条件を比較するような演算のことです。

自己結合+非等値結合

そして,そうした行間比較を行う場合,自己結合とほとんど常にセットで使われる演算が,非等値結合です。これは文字通り,結合条件に等号以外の<>や<=を使う結合方法で,多くの場合は不等号を使います。

たとえば,図1の部署テーブルに対して「自己結合+非等値結合」を使う例としてリスト6のようなコードが挙げられます。実行結果は図10のようになります。

リスト6 図1の部署テーブルに対して「自己結合+非等値結合」を実行

SELECT D1.dept_id, D2.dept_id
  FROM Departments D1 INNER JOIN Departments D2
    ON D1.dept_id >= D2.dept_id;

図10 リスト6の実行結果

画像

これは,D1およびD2のdept_idを比較して,D1の各dept_idの値に対して,それ以下となるD2のレコードを選択しています。この結果を見ると,D1.dept_idのグループについて含まれるレコード数がきれいに1つずつ増えていることがわかります(これは,部署テーブルの部署IDをたまたま連番で設定したためです)⁠

したがって,リスト7のようにD1.dept_idを集約キーとして集計することで,連番を生成できます図11)⁠

リスト7 自己非等値結合で連番生成

SELECT D1.dept_id, COUNT(*) AS seq
  FROM Departments D1 INNER JOIN Departments D2
    ON D1.dept_id >= D2.dept_id
 GROUP BY D1.dept_id;

図11 リスト7の実行結果

D1.dept_id seq
---------- ---
10         1
11         2
12         3
13         4

こういう自己結合の使い方は,昔からSQLの中級テクニックとして知られているものですが,ほかにも工夫するといろいろな応用が利くので,ぜひ覚えておいてほしいと思います。

演習問題

それでは,今月の演習問題を2つ出しましょう。

  • 問題①:リスト8「自己」クロス結合のコードは何行の結果を返すでしょう。
  • 問題②:その結果は具体的にどのような中身になるでしょう。

リスト8 演習問題用「自己」クロス結合のコード

SELECT D1.digit + (D2.digit * 10) + (D3.digit * 100) AS seq
  FROM Digits D1 CROSS JOIN Digits D2
                    CROSS JOIN Digits D3;

問題①には1秒で答えてください。問題②の制限時間は3分です。回答と解説は,筆者のWebページ内にある「SQL アタマアカデミー」サポートページに掲載しています。

終わりに

結合演算は,DBエンジニアにとって非常に有用で使用頻度も高い道具です。しかし,この演算はそれだけに,割と直観的な理解をされがちで,各種の結合がそれぞれどのような関係にあるのか,という点に注意が払われないことがよくあります。本稿が結合演算の理解の助けとなれば幸いです。

参考資料
ミック『達人に学ぶ SQL徹底指南書』
(翔泳社, 2008)

自己結合および外部結合については,⁠1-2 自己結合の使い方」および「1-5 外部結合の使い方」でさまざまな応用方法を紹介しています。本稿を読んで興味を持たれた方は,参照するとより深い理解が得られるでしょう。

COLUMN 結合の簡略的な書き方について

本稿では演算のタイプという観点から,クロス結合,内部結合,外部結合という3つの結合の関係を取り上げました(自己結合は,本文でも書いたように,筆者はあえて独自のカテゴリを作る必要はないと思っています)⁠

本文では取り上げませんでしたが,⁠~結合」という名前のついている演算として,⁠自然結合natural join)⁠があります。これは,次のような構文で記述します。

SELECT *
  FROM Employees NATURAL JOIN Departments;

自然結合においては結合条件は記述せず,暗黙に結合されるテーブルの同じ名前の列が等号で結ばれます。したがってこれを普通の内部結合で書き換えるとこうなります。

SELECT *
  FROM Employees E INNER JOIN Departments D
    ON E.dept_id = D.dept_id;

自然結合は,一応標準SQLで定義されている構文ですので,その点で方言性はなく,どの実装でも使えるのですが,筆者の個人的見解として,あえて使う必要はないと思います。自然結合のメリットは,頻繁に使う(=「自然」な)等値結合を短い記述量で書けるということですが,しかし別に内部結合で書いてもそんなに記述量が増えるわけでもありません。一方で,等値条件しか記述できない,列名が異なったりデータ型が違うと適用できない,などの制約がつくため,拡張性に乏しいというデメリットがあります。また,テーブルの定義をよく理解していないとクエリの結合条件が読み取れないため,可読性も良くありません。

この自然結合と内部結合の中間みたいな道具として,USING句というのもあります。上の2つと同等のクエリをUSINGを使って表現すると,こうなります。

SELECT *
  FROM Employees INNER JOIN Departments
 USING (dept_id);

この USING句も,標準SQLではありますが等値条件しか記述できず,テーブル間で列名が異なる場合もアウトという,自然結合とほとんど同じ位置づけになります。結合式で使う列名を明示している点で,可読性は自然結合よりマシなのですが…。

結論としては,普通に内部結合を使いましょう,ということで。

著者プロフィール

ミック

SI企業に勤務するDBエンジニア。主にデータウェアハウス業務に従事している。自身のサイト「リレーショナル・データベースの世界」でデータベースとSQLについての技術情報を公開している。『Web+DB Press』で「SQLアタマアカデミー」を連載中。

著書:『達人に学ぶ SQL徹底指南書』(翔泳社、2008)訳書:J.セルコ『SQLパズル 第2版』(翔泳社、2007)

SQLアタマアカデミー:サポートページ

コメント

コメントの記入