はじめに
Oracle 10gのSQLの新機能のmodel
句について、入門事項からOracle Technology Network(US)でよく見かける問題の解法まで、SQLのイメージを交えて解説します。本稿では、行の補完を行うmodel
句のサンプルを扱います。
対象読者
- OracleのSQLで
model
句を使いたい方 - OracleのSQLの理解を深めたい方
必要な環境
本稿で扱うSQLは、Oracle 11g R2(11.2.0.1.0)で動作確認しました。
1. 連番表の作成
1以上の整数の連番が欲しいことは、たまにあります。all_objects
やall_catalog
やdict
といった特に権限がなくてもアクセスできるデータディクショナリを使って連番表を作成することが多いですが、model
句の機能を使って連番表を作成してみます。
select soeji,dummy from dual model dimension by (1 as soeji) measures(0 as dummy) rules( dummy[for soeji in(1,2,3,4,5)]= 0);
soeji | dummy |
1 | 0 |
2 | 0 |
3 | 0 |
4 | 0 |
5 | 0 |
処理のイメージを解説すると、まず、model
句のdimension by (1 as soeji)
とmeasures(0 as dummy)
によって、soejiを添字として、0を要素名dummyとして持つ配列を用意してます。次に、model
句のrules
句でのdummy[for soeji in(1,2,3,4,5)]= 0
によって、soejiを添字とした配列の、添字の1,2,3,4,5のdummyに0をupsert(あればupdate、なければinsert)してます。
SQLのイメージは下図のようになります。dimension by (1 as soeji)
に対応する配列の添字を紫色で表現してます。
下記のように、位置参照を何度も使っても同じ結果を取得できますが、上記のdummy[for soeji in(1,2,3,4,5)]= 0
のようにfor
コンストラクトを使ったほうがシンプルなSQLとなります。
select soeji,dummy from dual model dimension by (1 as soeji) measures(0 as dummy) rules( dummy[1]= 0, dummy[2]= 0, dummy[3]= 0, dummy[4]= 0, dummy[5]= 0);
forコンストラクトでfrom toを使う方法
下記のように、for
コンストラクトでfrom to
を使って、開始値と終了値と増分値を指定することもできます。dummy[for soeji from 1 to 5 increment 1]= 0
は、開始値が1で終了値が5で増分値が1なので、soejiを添字とした配列の、添字の1,2,3,4,5のdummyに0がupsert(あればupdate,なければinsert)されます。
select soeji,dummy from dual model dimension by (1 as soeji) measures(0 as dummy) rules( dummy[for soeji from 1 to 5 increment 1]= 0);
iterateを使う方法
下記のように、iterate
を使って連番表を作成することもできます。rules iterate (5)
と記述すると、rules
が5回評価されます。そして、ruleが1回評価されるごとにインクリメントされる値として、iteration_number
があります。なお、iteration_number
は、0から開始されます。
下記のSQLでは、rules
が5回評価されますので、dummy[iteration_number+1] = 0
を指定して1から5までの連番を作成してます。
select soeji,dummy from dual model dimension by (1 as soeji) measures(0 as dummy) rules iterate (5) (dummy[iteration_number+1] = 0);
ちなみに、プログラム言語のfor
文のループ変数でよく使われるiは、iterationの頭文字が由来だそうです。
for (int i = 0; i <= 10; i++) System.out.println("Hello World");
再帰with句を使う方法
下記のSQLのように、Oracle 11g R2の新機能の再帰with
句を使用して連番表を作成することもできます。model
句と使い分けるといいでしょう。
with rec(soeji) as( select 1 from dual union all select soeji+1 from rec where soeji+1 <= 5) select * from rec;