分析函數語法:
FUNCTION_NAME(<argument>,<argument>...) OVER (<Partition-Clause><Order-by-Clause><Windowing Clause>)
例:
sum(sal) over (partition by deptno order by ename) new_alias
解析:
sum就是函數名;(sal)是分析函數的參數,每個函數有0~3個參數,參數可以是表達式,例如:sum(sal+comm);over 是一個關鍵字,用於標識分析函數,否則查詢分析器不能區別sum()聚集函數和sum()分析函數;partition by deptno 是可選的分區子句,如果不存在任何分區子句,則全部的結果集可看作一個單一的大區;order by ename 是可選的order by 子句,有些函數需要它,有些則不需要
測試:
建表:
-- Create table create table SCOTT.T_TEST_ORDER ( cust_nbr NUMBER, region_id NUMBER, salesperson_id NUMBER, year NUMBER, month NUMBER, tot_orders NUMBER, tot_sales NUMBER ) tablespace USERS pctfree 10 initrans 1 maxtrans 255 storage ( initial 64K next 1M minextents 1 maxextents unlimited );
插入數據:
11 7 11 2001 7 2 12204 4 5 4 2001 10 2 37802 7 6 7 2001 2 3 3750 10 6 8 2001 1 2 21691 10 6 7 2001 2 3 42624 15 7 12 2000 5 6 24 12 7 9 2000 6 2 50658 1 5 2 2000 3 2 44494 1 5 1 2000 9 2 74864 2 5 4 2000 3 2 35060 2 5 4 2000 4 4 6454 2 5 1 2000 10 4 35580 4 5 4 2000 12 2 39190
查詢:
select cust_nbr,region_id, sum(tot_sales), sum(sum(tot_sales)) over(partition by region_id) from scott.t_test_order --where year = 2001 group by region_id, cust_nbr;
分析一下:首先,以region_id ,cust_nbr 這倆字段組合分組,計算出每組 tot_sales 的和,然后又以 region_id 作為分組條件,在原來求和的基礎上又進行求和,得到最終數據(這個思路值得借鑒)。
請注意上面的綠色高亮部分,group by的意圖很明顯:將數據按區域ID,客戶進行分組,那么Over這一部分有什么用呢?假如我們只需要統計每個區域每個客戶的訂單總額,那么我們只需要group by o.region_id,o.cust_nbr就夠了。但我們還想在每一行顯示該客戶所在區域的訂單總額,這一點和前面的不同:需要在前面分組的基礎上按區域累加。很顯然group by和sum是無法做到這一點的(因為聚集操作的級別不一樣,前者是對一個客戶,后者是對一批客戶)。這就是over函數的作用了!它的作用是告訴SQL引擎:按區域對數據進行分區,然后累積每個區域每個客戶的訂單總額(sum(sum(o.tot_sales)))。
上面的sql統計分析了 每個客戶及其對應區域的訂單總額
下面篩選那些個客戶訂單總額占到區域訂單總額20%以上
select * from ( select cust_nbr,region_id, sum(tot_sales) a , sum(sum(tot_sales)) over(partition by region_id) b from scott.t_test_order --where year = 2001 group by region_id, cust_nbr )a_t where a_t.a>a_t.b*0.2;
如果我們想要知道每個大客戶所占的訂單比例呢?
select a_t.*,round(a_t.a/a_t.b,2)*100||'%' precend from ( select cust_nbr,region_id, sum(tot_sales) a , sum(sum(tot_sales)) over(partition by region_id) b from scott.t_test_order --where year = 2001 group by region_id, cust_nbr )a_t where a_t.a>a_t.b*0.2;