Oracle 11g學習筆記--privot和unpivot子句
Oracle 11g學習筆記–privot和unpivot子句
pivot子句是Oracle database 11g的新增特性,可以在查詢輸出中將行旋轉為列,同時對資料使用聚合函式。同時新增了unpivot子句,他可以在查詢輸出中將列旋轉為行;
引入
現在有以下表資料:
(未顯示完全。。。)
現在我們想觀察(1, 2, 3)每種型別id在前四月的銷售情況;
你可能會這麼寫sql:
select prd_type_id, month, sum(amount)
from all_sales
where month <= 4 and prd_type_id in (1, 2, 3)
group by month,prd_type_id
order by prd_type_id;
但是這種顯示結果也許並不清晰,想想如果把月份橫著排列是不是更清晰,若用一般方法我們可以這樣寫:
select
prd_type_id,
sum(decode(month, 1, amount, 0)) as JAN,
sum(decode(month, 2, amount, 0)) as FEB,
sum(decode(month, 3, amount, 0)) as MAR,
sum(decode(month, 4, amount, 0 )) as APR
from all_sales
where prd_type_id in(1, 2, 3) group by prd_type_id;
--不熟悉decode函式的可以用一下方法
select
prd_type_id,
sum(case when month = 1 then amount else 0 end) as JAN,
sum(case when month = 2 then amount else 0 end) as FEB,
sum(case when month = 3 then amount else 0 end ) as MAR,
sum(case when month = 4 then amount else 0 end) as APR
from all_sales
where prd_type_id in (1, 2, 3)
group by prd_type_id;
這樣顯示是不是更好呢?但是現在oracle 11g為我們提供了更好的方法, 那就是pivot,他可以將行變成列:
select *
from (
-- ①
select month, prd_type_id, amount
from all_sales
where year = 2003
and prd_type_id in(1, 2, 3)
)
pivot(
-- ②
sum(amount) for month in (1 as JAN, 2 as FEB, 3 as MAR, 4 as APR)
)
order by prd_type_id;
執行結果同上圖;
接下來,我將講講這些程式碼的含義(只是個人理解):
對於①我的理解是,這部分限定了資料的範圍,這個範圍怎麼確定呢,首先你得知道你想顯示什麼。在本文中,你需要顯示prd_type_id, month, amount三種資料,所以就可以確定了;
對於②我的理解是,這部分規定了如何將行變成列;對於sum(amount)的含義,我們先放放,先說說這個month,他就規定了把什麼變成從行變成列了,那麼in後面的部分,則規定了,哪些month需要變成列,而as規定了別名,可以省略。那麼對於sum(amount)怎麼理解呢,首先他必須是聚合操作,他就是要在每一個month列下要顯示的資料,拿一月來說,他下面的資料肯定不止一條,這也是為什麼要使用聚合函式的原因了, 他到底對得是哪些amount的求和?我們知道在本題中,還有些列並未轉成行,那麼這些列同上面的月份便共同規定了對哪些amount求和了,如一月與id=1對應的那個格子,就是所有滿足月份為一月,而型別id為1的資料了;
轉換多個列
我們都知道for後面規定了哪些行將被轉換為列,而in裡面規定了要將哪些特定的行轉換,有了這些,我們便不能理解下面的sql:
select *
from (
select month, prd_type_id, amount
from all_sales
where year = 2003 and prd_type_id in(1,2,3)
)
pivot (
sum(amount) for(month, prd_type_id) in(
(1, 1) as jan_prd_type_1,
(2, 2) as feb_prd_type_2,
(3, 3) as mar_prd_type_3,
(4, 2) as apr_prd_type_2
)
);
在轉換中使用多個聚合函式
select *
from (
select month, prd_type_id, amount
from all_sales
where year = 2003
and prd_type_id in(1, 2, 3)
)
pivot (
sum(amount) as sum_amount,
avg(amount) as avg_amount
for(month) in(
1 as JAN, 2 as FEB
)
)
order by prd_type_id;
值得注意的是系統會自動將兩個別名合為一個;
unpivot子句
unpivot子句的作用是將列轉換為行。
現有表格資料如下:
select * from pivot_sales_data
unpivot(
amount for month in (jan, feb, mar, apr)
)
order by prd_type_id;