1. 程式人生 > >oracle sql 高階程式設計學習筆記(二十一)

oracle sql 高階程式設計學習筆記(二十一)

一、行求解順序

select product, country, year, week, inventory, sale, receipts
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory' 
   model return updated rows 
   partition by(product, country)
   dimension by(year, week)
   measures(0 inventory, sale, receipts) rules automatic
   order
(inventory [ year, week ] = nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]) order by product, country, year, week;

對於列中求出每週的庫存,我們把 automatic order 註釋掉 ,
automatic order 允許資料庫自動識別規則之間的依賴關係
會啟用預設的排序sequential order 規則排序, 既rules中規則先後順序
sql語句會報如下錯誤
ORA-32637: 順序排序 MODEL 中的自迴圈規則
這裡寫圖片描述


這是因為 程式碼inventory [ cv(year), cv(week) - 1 ]子句進行了跨行引用,庫存列的值必須按照周的升序來進行計算,
例如 第二週的庫存必須在得到第一週的庫存值後才能進行計算。

當然除了使用 automatic order 我們也可以直接在規則進行排序

select product, country, year, week, inventory, sale, receipts
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory' 
   model return updated rows
partition by(product, country) dimension by(year, week) measures(0 inventory, sale, receipts) rules /*automatic order*/ (inventory [ year, week ] order by year,week asc --通過order自己顯示聲明瞭行求解順序 = nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ] ) order by product, country, year, week;

二、規則求解順序

select * from (select product, country, year, week, inventory, sale, receipts
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory'
     model return updated rows 
   partition by(product, country)
   dimension by(year, week)
   measures(0 inventory, sale, receipts) 
   rules sequential order
   (inventory [ year, week ] order by year,week asc   
    = nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
    ,
    receipts[year in(2000,2001),week in (51,52,53)] 
        order by year ,week asc  -- 這裡排序不能少  不然因為上面規則中涉及到跨行處理 不然還是會報 ORA-32637錯誤
=receipts[cv(year),cv(week)]*10
   ) 

 order by product, country, year, week)
 where week>50 --用於篩選修改的receipts,便於檢視結果;

這裡寫圖片描述

從結果中明顯看到,先按照求解庫存後,再重新計算收入receipts

三、聚合函式

select product, country, year, week, inventory, sale, receipts, avg_inventory, max_sale
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory'
     model return updated rows 
   partition by(product, country)
   dimension by(year, week)
   measures(0 inventory,0 avg_inventory,0 max_sale, sale, receipts) 
   rules  automatic order
   (inventory [ year, week ] 
    = nvl(inventory [ cv(year), cv(week) - 1 ], 0) - sale [ cv(year), cv(week) ] + receipts [ cv(year), cv(week) ]
    ,
    avg_inventory[year,any]=round(avg(inventory)[cv(year),week],2),
    max_sale[year,any]=max(sale)[cv(year),week]
   ) 

 order by product, country, year, week

avg_inventory[year, ANY] = avg(inventory)[cv(year) , week ],用ANY是因為右側的表示式對於所有的week都會返回相同的值,所以沒必要重複計算,對於所有的week只需要計算一次就行了。Avg後面的[cv(year) , week ]表示聚合的範圍是這一年和所有周。
這裡寫圖片描述

四、迭代

1、例項演示

select  year, week, sale, sale_list
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory'
     model return updated rows 
   partition by(product, country)
   dimension by(year, week)
   measures( cast('' as varchar2(50))sale_list, sale ) 
   rules  iterate(5)-- 規則會迭代5次,ITERATION_NUMBER從04。
   ( sale_list[year,week] order by year,week asc=
    sale[cv(year),cv(week)-iteration_number+2]||--cv(week)-iteration_number+2 來訪問前兩週和後兩週的資料
    case when iteration_number=0 then '' else ',' end||
-- case語句在為每個列表中除了第一個成員外每個成員都加上逗號。
      sale_list[cv(year),cv(week)]    
   ) 

 order by  year, week

這裡寫圖片描述

同樣這也是列轉行 可以通過pivot函式實現

2、空值

語法
presentv(cell_reference,expr1,expr2)
表示 如果 cell_reference存在,則返回 expr1,不存在則返回expr2
PRESENTNNV(NOT NULL VALUE)
用法同PRESENTV,只是多了非空條件。
PRESENTNNV(t , v1 , v2) 如果單元格t存在且非空,返回v1,否則,返回v2。

接著示列中的例子

select  year, week, sale, sale_list
  from sales_fact
 where country = 'Australia'
   and product = 'Xtend Memory'
     model return updated rows 
   partition by(product, country)

   dimension by(year, week)
   measures( cast('' as varchar2(50))sale_list, sale ) 
   rules  iterate(5)
   ( sale_list[year,week] order by year,week asc=
   presentv(
     sale[cv(year),cv(week)-iteration_number+2],
     sale[cv(year),cv(week)-iteration_number+2]||
        case when iteration_number=0 then '' else ',' end||
         sale_list[cv(year),cv(week)],
      sale_list[cv(year),cv(week)] )  
   ) 

 order by  year, week

結果解決了 示列中存在雙逗號問題。
這裡寫圖片描述