Oracle 11g學習筆記--model子句

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()獲取當前月份,其值爲1sales_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.252

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.252), 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.252), 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年的數據了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章