Oracle 11g學習筆記–model子句
oracle 10g中新增的model子句可以用來進行行間計算。model子句允許像訪問數組中元素那樣訪問記錄中的某個列,這就提供了諸如電子表格計算之類的計算能力;
先來看一個簡單的例子:
select
prd_type_id, year, month, sales_amount
from all_sales
where prd_type_id between 1 and 2 and emp_id = 21
model
partition by (prd_type_id)
dimension by (month, year)
measures (amount sales_amount) (
sales_amount[1, 2004] = sales_amount[1, 2003],
sales_amount[2, 2004] = sales_amount[2, 2003] + sales_amount[3, 2003],
sales_amount[3, 2004] = round(sales_amount[3, 2003] * 1.25, 2)
)
order by prd_type_id, year, month;
partition by(prd_type_id)指定結果是根據prd_type_id分區的,所謂的分區就是在prd_type_id不等的情況下,一下的定義數組是互相不能訪問的;
dimension by(month, year) 定義數組的維數是month, year,這就意味着必須提供月份和年份才能訪問數組中的單元;
measures(amount sales_amount)表明數組中的每個單元包含一個數量,同時表明數組名爲sales_amount.爲了訪問sales_amount數組中標示2003年1月的那個單元,可以使用sales_amount[1, 2003],返回指定年月的銷量。
執行結果:
圖中的所有2004年的數據就是通過model生成出來的;
補充:對於數組的訪問方式,還可以顯示的訪問,如sales_amount[1, 2003]可以顯示指定維度sales_amount[month = 1, year = 2003],但是這種方式明顯更復雜。必須提一下的是兩者的區別:他們處理維度中空值得方式是不同的,例如sales_amount[null, 2003]返回月份爲空值,年份爲2003的銷量,而sales_amount[month = null, year = 2003]則不會返回任何有效數據,因爲null=null的返回值總是false;
對於數組角標的維度還可以通過以下擴展方法:
1.between 和 and :
--將2004年1月的銷量設置爲2003年1月至3月的銷量的平均值取整;
sales_amount[1, 2004] = round(sum(sales_amount)[month between 1 and 3, 2003], 2);
2.any 和 isany
--表示將2004年1月的銷量設置爲所有年份月份的銷量值和取整
sales_amount[1, 2004] = round(sum(sales_amount)[any, year is any], 2);
3.currentv()
該函數用於獲的某個維度的當前值。
--表示將2004年第一個月的銷量設置爲2003年同月銷量的1.25倍。注意此處用currentv()獲取當前月份,其值爲1;
sales_amount [1, 2004] = round(sales_amount[currentv(), 2003] *1.25, 2)
4.for循環
該表達式將2004年前三個月的銷量設置爲2003年相應月份銷量的1.25倍。其中increment 1表示了變量每次循環+1
sales_amount[for month from 1 to 3 increment 1, 2004] = round (sales_amount[currentv(), 2003] * 1.25, 2)
5.處理空值和缺失值
■使用is present
當數據單元指定的單位在model子句執行之前存在,則is precent返回ture.
sales_amount[for month from 1 to 3 increment 1, 2004] =
case when sales_amount[currentv(), 2003] is present
then
round (sales_amount[currentv(), 2003] * 1.25, 2)
else
0
end
■presentv()
如果cell引用的記錄在model子句執行之前就存在,那麼presentv(cell, expr1, expr2)返回表達式expr1。如果這條記錄不存在,則返回表達式expr2。
sales_amount[for month from 1 to 3 increment 1, 2004] = presentv(sales_amount[currentv(), 2003],
round(sales_amount[currentv(), 2003] * 1.25, 2), 0)
■presentnnv
presentnnv(cell, expr1, expr2)如果cell引用的單元在model子句執行之前已經存在,並且該單元的值不爲空,則返回表達式expr1。如果記錄不存在,或單元值爲空,則返回表達式expr2;
sales_amount[for month from 1 to 3 increment 1, 2004] = presentnnv(sales_amount[currentv(), 2003],
round(sales_amount[currentv(), 2003] * 1.25, 2), 0)
■ignore nav 和 keep nav
此關鍵詞使用在 model後面;
ignore nav返回值如下:
●空值或缺失數字值時返回0
●空值或缺失字符串值時返回空值字符串
●空值或缺失日期值時返回01-jan-2000。
●其它所有數據庫類型時返回空值
keep nav對空值或缺失數字值返回空值,默認條件;
select .....
from table
model ignore nav
paratition by ....
dimension by ....
measures .......
更新已有的單元
默認情況下,如果表達式左端的引用單元存在,則更新該單元。如果該單元不存在,就在數組中創建一條新的記錄。可以用rules update 改變這種默認行爲,支出在單元不存在的情況下不創建新紀錄;
爲了驗證效果,我們引用本文開頭的代碼:
select
prd_type_id, year, month, sales_amount
from all_sales
where prd_type_id between 1 and 2 and emp_id = 21
model
partition by (prd_type_id)
dimension by (month, year)
measures (amount sales_amount)
rules update (
sales_amount[1, 2004] = sales_amount[1, 2003],
sales_amount[2, 2004] = sales_amount[2, 2003] + sales_amount[3, 2003],
sales_amount[3, 2004] = round(sales_amount[3, 2003] * 1.25, 2)
)
order by prd_type_id, year, month;
引用從圖中可以看出已經沒有2004年的數據了;