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;