MySQLで、Oracleの分析関数と同じ結果を取得する1
山岸賢治 [著] 2008/11/11 14:00

SourceCode 2.71 KB

 連載「分析関数の衝撃」では、Oracleの分析関数を主に扱いました。「分析関数の衝撃」の外伝となるこの連載では、 MySQLで、Oracleの分析関数と同じ結果を取得するSQLの考え方と、処理のイメージを解説します。

1 2 3 4 →

はじめに

 本稿では、Oracleの分析関数の中で、Rows指定およびRange指定なしのsum関数、Rank関数、dense_Rank関数と同じ結果を取得するSQLを扱います。

対象読者

  • MySQLやPostgreSQLで、分析関数と同じ結果を取得するSQLを書きたい方
  • OracleやDB2やSQLServerの、分析関数の理解を深めたい方

 本稿では、相関サブクエリを多用しますので、『相関サブクエリで行と行を比較する』を先に読んでおくと理解が進むと思います。

必要な環境

 本稿で扱うSQLは、MySQL 5.1.28で動作確認しました。ソースコードはPostgreSQL 8.3とOracle 10.2.0.1.0でも動作確認しました。その他、次の環境でも応用が可能です。

  • SQLServer
  • DB2

1. IDごとのValの合計を求める

 最初は、IDごとにValの合計を求めるSQLについてです。まずは、テーブルのデータと、出力結果を考えます。

IDTable
IDSeqVal
AA1100
AA2100
AA3500
AA4200
AA5200
AA650
BB1200
BB2400
BB3800
BB4900
CC1100
CC2800
CC3700
DD1400
EE150
FF110
FF320
FF540
FF680

 IDごとのValの合計を求めます。言いかえれば、Oracleの下記の分析関数を使ったSQLと同じ結果を取得します。

分析関数を使ったSQL
select ID,Seq,Val,
sum(Val) over(partition by ID) as sumVal
  from IDTable
order by ID,Seq;
出力結果
IDSeqValsumVal
AA11001150
AA21001150
AA35001150
AA42001150
AA52001150
AA6501150
BB12002300
BB24002300
BB38002300
BB49002300
CC11001600
CC28001600
CC37001600
DD1400400
EE15050
FF110150
FF320150
FF540150
FF680150

 partition by IDという指定をして、IDごとのValの合計を求めていますので、答えは相関サブクエリを使った下記となります。

相関サブクエリを使う方法
select ID,Seq,Val,
(select sum(b.Val)
   from IDTable b
  where b.ID = a.ID) as sumVal
  from IDTable a
order by ID,Seq;

 相関サブクエリでwhere b.ID = a.IDを指定して、外側のselect文の結果と同じIDを条件として、sum関数でValの合計を求めてます。結果としてIDごとのValの合計が求まります。別解として、内部結合を使う方法もあります。

内部結合を使う方法
select a.ID,a.Seq,a.Val,b.sumVal
  from IDTable a,
       (select ID,
        sum(Val) as sumVal
          from IDTable
        group by ID) b
 where b.ID = a.ID
order by a.ID,a.Seq;

 インラインビューでIDごとのValの合計を求めておいて、IDの一致を結合条件として内部結合させています。

 SQLのイメージは下記となります。

SQLのイメージ
SQLのイメージ

 なお、内部結合を使う方法であれば、例えば、IDごとのValの最大値と行数も欲しい場合は、下記のように列を追加するだけでよいです。

select a.ID,a.Seq,a.Val,b.sumVal,b.maxVal,b.cnt
  from IDTable a,
       (select ID,
        sum(Val) as sumVal,
        max(Val) as maxVal,
        count(*) as cnt
          from IDTable
        group by ID) b
 where b.ID = a.ID
order by a.ID,a.Seq;

出力結果
IDSeqValsumValmaxValcnt
AA110011505006
AA210011505006
AA350011505006
AA420011505006
AA520011505006
AA65011505006
BB120023009004
BB240023009004
BB380023009004
BB490023009004
CC110016008003
CC280016008003
CC370016008003
DD14004004001
EE15050501
FF110150804
FF320150804
FF540150804
FF680150804

1 2 3 4
→
INDEX
MySQLで分析関数を模倣1(前編)
Page1
はじめに
対象読者
必要な環境
1. IDごとのValの合計を求める
2. IDごとのValの累計を求める
3. IDごとのValの順位(Rank)を求める
4. IDごとのValの順位(dense_Rank)を求める
最後に
参考資料
プロフィール
山岸賢治 ヤマギシケンジ

Oracle ACEの1人。
OracleSQLパズルの運営者。
ORACLE MASTER Silver Oracle Database 10g
(研修受講で)ORACLE MASTER Gold Oracle Database 10g
ソフトウェア開発技術者 (情報処理技術者試験)
第二種情報処理技術者 (情報処理技術者試験)
 


記事へのコメント・トラックバック機能は2011年6月に廃止させていただきました。記事に対する反響はTwitterやFacebook、ソーシャルブックマークサービスのコメントなどでぜひお寄せください。

スポンサーサイト