Model語句是Oracle 10g的新功能之一。 本文通過一些簡單的例子幫助理解Model語句的用法,復雜使用場景請參考其他文章。
環境:當然需要Oracle 10g以上,本人是在11g上測試的。
1. 什么是model語句
model語句是Oracle10g的新功能,可以在select語句里面像其他編程語言操作數組一樣,對SQL的結果集進行處理。執行順序是位於Having之后。
1. from語句
2. where語句 (結合條件)
3. start with語句
4. connect by語句
5. where語句
6. group by語句
7. having語句
8. model語句
9. select語句
10. union、minus、intersect等集合演算演算
11. order by語句
model的好處
Oracle 9i為止,需要使用各種計算分析函數,union all等,以及借助其他
開發語言(C#及Java等)進行復雜計算統計合並等。使用Model之后,這些都可以在SQL里面進行了。
model典型使用場景
。
- 合計行追加
- 行列變換
- 使用當前行的前后行
RegExp_Replace函數的循環執行
2. HelloWorld
先看一個簡單的例子。
select ArrValue,soeji
from (select 'abcdefghijklmn' as ArrValue, 1 as soeji from dual)
model
dimension by(soeji)
measures(ArrValue)
rules(ArrValue[1] = 'Hello World');
ArrValue | soeji |
Hello World | 1 |
說明:
model model語句的關鍵字,必須
。
dimension by dimension維度的意思,可以理解為數組的索引,必須
。
measures 指定作為數組的列
rules 對數組進行各種操作的描述。
例句1的理解:
select 'abcdefghijklmn' as ArrValue,
1 as soeji from dual;
abcdefghijklmn | 1 |
根據下面語句
model
dimension by (soeji)
measures(ArrValue)
soeji作為索引對數組ArrValue進行操作,rules(ArrValue[1] = 'Hello World')就是說
用Hello World覆蓋ArrValue[1]里面的值。
在看一個例子,例句2:
select ArrValue,soeji
from (select 'abcdefghijklmn' as ArrValue,
1 as soeji from dual)
model
dimension by(soeji)
measures(ArrValue)
rules(ArrValue[1] = 'Hello World',
ArrValue[2] = 'Hello model');
Hello World | 1 |
Hello model | 2 |
rules的缺省行為是存在就更新,不存在則追加
,因此,ArrValue[1] = 'Hello World'是更新一條,
ArrValue[2] = 'Hello Model'
insert一條。
再看一個例子,例句3:
select ArrValue,soeji from (select 'abcdefghijklmn' as ArrValue, 1 assoeji from dual) model dimension by(soeji) measures(ArrValue) rules(ArrValue[3] ='Hello Oracle');
abcdefghijklmn | 1 |
Hello Oracle | 3 |
model語句里面,索引可以是不連續的。

再看一個例子,例句4:
select ArrValue,soeji from (select 'abcdefghijklmn' as ArrValue, 1 assoeji from dual) model return updated rows dimension by(soeji) measures(ArrValue) rules(ArrValue[4] = 'Hello CodeZine');
Hello CodeZine | 4 |
使用model return updated rows的話,被
rules
更新或者插入的行才顯示,沒有更新過的行不再作為SQL的結果。
ID | Val |
1 | 30 |
2 | 100 |
3 | 50 |
4 | 300 |
select ID,Val
from addTotal
model
dimension by(ID)
measures(Val)
rules( Val[null] = Val[1]+Val[2]+Val[3]+Val[4] );
ID | Val |
1 | 30 |
2 | 100 |
3 | 50 |
4 | 300 |
null | 480 |
不使用model的話可以使用
rollup
,union all等實現
。
select ID,sum(Val) as Val from addTotal group by rollup(ID);
union all方式:
select ID,Val from addTotal union all select null,Sum(Val) from addTotal;
=================================================
以產品產量表為例,一個工廠(用code表示)生產多種產品(用p_id表示),每種產品具有生產量(v1)和銷售量(v2)
產品代碼具有審核關系,比如’10’=’30’+’31’,其中’10’代表大類,’30’和’31’代表’10’大類下的小類。
SQL> create table t603 (code varchar(10),p_id varchar(7),v1 number(10),v2 number(10));
Table created.
SQL> insert into t603 values(’600001’,’30’,1,1);
SQL> insert into t603 values(’600001’,’31’,1,1);
SQL> insert into t603 values(’600001’,’10’,2,2);
SQL> insert into t603 values(’600002’,’10’,3,2);
SQL> insert into t603 values(’600002’,’31’,2,1);
SQL> insert into t603 values(’600002’,’30’,2,1);
SQL> commit;
Commit complete.
SQL> select * from t603;
CODE P_ID V1 V2
600001 30 1 1
600001 31 1 1
600001 10 2 2
600002 10 3 2
600002 31 2 1
600002 30 2 1
6 rows selected.
SELECT code,
p_id, v1
FROM t603
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id)
MEASURES (v1)
RULES (
v1[’err1’] = v1[’30’] + v1[’31’] -v1[’10’])
ORDER BY code, p_id;
其中rule表示計算規則,’err1’表示這條審核關系的代號,它的值等於P_ID為’30’的v1值+P_ID為’31’的v1值-P_ID為’10’的v1值
PARTITION BY (code)表示按工廠分區,即審核在一個工廠內的產品
MODEL 關鍵字后面的 RETURN UPDATED ROWS 子句將結果限制為在該查詢中創建或更新的那些行。使用該子句是使結果集只包含新計算的值,在本例中就是審核結果
CODE P_ID V1
600001 err1 0
600002 err1 1
如果返回值=0,表示v1[’30’] + v1[’31’] =v1[’10’]審核通過,否則,審核不通過
SELECT code,
p_id, v1,v2
FROM t603
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id)
MEASURES (v1,v2)
RULES (
v1[’err1’] = v1[’30’] + v1[’31’] -v1[’10’],
v2[’err1’] = v2[’30’] + v2[’31’] -v2[’10’])
ORDER BY code, p_id;
CODE P_ID V1 V2
600001 err1 0 0
600002 err1 1 0
如果表格中包含多個維度的數據,比如時間,多個維度都可以編寫規則,比如2008年的審核關系
SELECT year,code,
p_id, v1
FROM t603_1
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id,year)
MEASURES (v1)
RULES (
v1[’err1’,2008] = v1[’30’,2008] + v1[’31’,2008] -v1[’10’,2008])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2008 600001 err1 0
2008 600002 err1 1
如果維度不影響規則,也可以只分區,而沿用原來的規則
SELECT year,code,
p_id, v1
FROM t603_1
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code,year)
DIMENSION BY (p_id)
MEASURES (v1)
RULES (
v1[’err1’] = v1[’30’] + v1[’31’] -v1[’10’])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2008 600001 err1 0
2008 600002 err1 1
SQL> create table t603_2 as select * from t603_1;
Table created.
SQL> insert into t603_2 select ’2007’ year,code,p_id,v1,v2 from t603_1;
6 rows created.
如果表中具有多個年份的數據,每個年份的審核結果都能顯示
SELECT year,code,
p_id, v1
FROM t603_2
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code,year)
DIMENSION BY (p_id)
MEASURES (v1)
RULES (
v1[’err1’] = v1[’30’] + v1[’31’] -v1[’10’])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2008 600001 err1 0
2007 600001 err1 0
2007 600002 err1 1
2008 600002 err1 1
規則也可以是多個維度不同取值,本例假定不同年份之間比較,比如要求2008年的’10’=2007年的’30’+’31’
SELECT year,code,
p_id, v1
FROM t603_2
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id,year)
MEASURES (v1)
RULES (
v1[’err1’,2008] = v1[’30’,2007] + v1[’31’,2007] -v1[’10’,2008])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2008 600001 err1 0
2008 600002 err1 1
如果年份很多,每個年份都是和上年比較,這種描述可以用CV()函數簡化
SQL> insert into t603_2 select ’2006’ year,code,p_id,v1,v2 from t603_1;
SELECT year,code,
p_id, v1
FROM t603_2
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id,year)
MEASURES (v1)
RULES (
v1[’err1’,for year in( 2007 ,2008)] = v1[’30’,CV(year)-1] + v1[’31’,CV(year)-1] -v1[’10’,CV(year)])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2007 600001 err1 0
2008 600001 err1 0
2007 600002 err1 1
2008 600002 err1 1
如果year是數值類型,還可以用for year from 2007 to 2009 increment 1的語法,如果是其他類型,還可以用在in子句帶子查詢的辦法,
比如for year in (select year from t603_2)。
但需要注意不能采用year in 的語法,year in的語法只能符號引用已經存在的單元格,而v1[’err1’,x]是新單元格。
單個年份的寫法如下:
SELECT year,code,
p_id, v1
FROM t603_2
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id,year)
MEASURES (v1)
RULES (
v1[’err1’,2008] = v1[’30’,CV()] + v1[’31’,CV()] -v1[’10’,CV()])
ORDER BY code, p_id;
YEAR CODE P_ID V1
2008 600001 err1 0
2008 600002 err1 1
而
SELECT year,code,
p_id, v1
FROM t603_2
WHERE code IN (’600001’,’600002’)
MODEL RETURN UPDATED ROWS
PARTITION BY (code)
DIMENSION BY (p_id,year)
MEASURES (v1)
RULES (
v1[’err1’,year in (’2008’)] = v1[’30’,CV()] + v1[’31’,CV()] -v1[’10’,CV()])
則返回0行