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行
