[Oracle] 相関サブクエリー

2013年8月6日

 これまた Oracle 独特というわけではないですが。先の「Order by 句に Select 文」で相関サブクエリーが出てきたのでちょっと整理がてら。

 相関サブクエリーとは、サブクエリー(子クエリー)に親クエリーの列名が出てくるタイプのサブクエリーです。

 たとえばよくあるハマりどころとして。
 Group by でグループごとの最大値を得ようとしたとします。

SQL> select JOB, max(SAL)
  2    from EMP
  3   group by JOB;

JOB                  MAX(SAL)
------------------ ----------
CLERK                    1300
SALESMAN                 1600
PRESIDENT                5000
MANAGER                  2975
ANALYST                  3000

 ここまではいいのですが、「じゃあ誰が(どのレコードが)最大なんだ?」とか思って以下のように書いてもエラーです。

SQL> select JOB, max(SAL), ENAME
  2    from EMP
  3   group by JOB;
select JOB, max(SAL), ENAME
                      *
行1でエラーが発生しました。:
ORA-00979: GROUP BYの式ではありません。

 ここで登場するのが相関サブクエリーです。以下のように書くと目的が達成できます。

SQL> select JOB, SAL, ENAME
  2    from EMP a
  3   where SAL = (select max(SAL)
  4                  from EMP b
  5                 where a.JOB = b.JOB);

JOB                       SAL ENAME
------------------ ---------- --------------
SALESMAN                 1600 ALLEN
MANAGER                  2975 JONES
ANALYST                  3000 SCOTT
PRESIDENT                5000 KING
ANALYST                  3000 FORD
CLERK                    1300 MILLER

 サブクエリー側の条件(where 句)に親クエリーの列名が出てきています。こういうのを相関サブクエリーと呼ぶらしいです。
 また、今回の例だと、この where 句が Group by 句と同じ役割を担っています。
 (ANALYST が複数行取得されているのは、同額の人が複数いるからですね)

 

 ところでこの相関サブクエリー。手続き型言語(C#)で等価コードを書くとこんな感じ。

// 親クエリーのループ(from 句)
foreach (var a in EMP)
{
    // 子クエリーの select の結果 (子クエリーの戻り値)
    int maxSal = int.MinValue;

    // 子クエリーのループ(from 句)
    foreach (var b in EMP)
    {
        // 子クエリーの Where 句
        if (a.JOB == b.JOB) //← a.JOB と同じ内容のものが集計対象になる
        {
            // max集計関数 (子クエリーの select)
            if (maxSal < b.SAL) maxSal = b.SAL;
        }
    }

    //-------------------------------------------

    // 親クエリーの Where 句
    if (maxSal == a.SAL)
    {
        // 親クエリーの select 
        Console.WriteLine("{0},{1},{2}", a.JOB, a.SAL, a.ENAME);
    }
}

 わりと手続き型そんまんまです。スコープも含めて。(上記コードでは null とか無視ですが)
 なので、相関サブクエリーにぶち当たってわからなかったら、手続き型的に読み直して理解してみる、というのも手かもしれません。






カテゴリー: Oracle, データベース

Follow comments via the RSS Feed | Leave a comment | Trackback URL

コメントを投稿する

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


«   »
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org