1. 程式人生 > 實用技巧 >oracle行轉列之動態列

oracle行轉列之動態列

首先我們來看下oracle的行轉列函式:

pivot 函式官方解釋:https://www.oracle.com/cn/database/articles/technology/pivot-and-unpivot.html

首先我們建立相關表及資料

create table TEST_DATA
(
  goods_name   VARCHAR2(32),
  budget_date  VARCHAR2(32),
  budget_money NUMBER
);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('泡麵', '2020-01', 20);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('泡麵', '2020-02', 50);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('泡麵', '2020-03', 60);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('火腿', '2020-01', 210);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('火腿', '2020-02', 530);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('火腿', '2020-03', 640);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('牛奶', '2020-01', 120);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('牛奶', '2020-02', 160);
insert into test_data (GOODS_NAME, BUDGET_DATE, BUDGET_MONEY)values ('牛奶', '2020-03', 140);

 我們的資料是這樣的:

我們需要的結果是:

名稱  2020-01  2020-02  2020-03  .。。。

泡麵  20      50    60

火腿  210     530    640

牛奶  120     650    140

假如我們知道我們要轉換的列為 2020-01 至2020-03 這時可以做如下轉換:

select * from test_data 
pivot (sum(budget_money) for budget_date in('2020-01','2020-02','2020-03'));

  

但是當月份不確定時,上面這種寫法就不適用了。我們檢視官方文件後發現pivot操作中的另一個子句XML

可用於解決此問題。該子句允許您以 XML 格式建立執行了pivot操作的輸出。這個時候我們將上面查詢語句改造之後如下:

select * from test_data 
pivot xml (sum(budget_money) for budget_date in(select budget_date from  test_data));

  

該語句在不同版本的plsql中型別不同,在plsql14001961版本中顯示xmltype型別。

這時檢視budget_date_xml的值發現會將表中所有月份展示,結果如下

當我高興的認為我的問題解決了之後,我發現我草率了。

將sql放到mybatis中查詢出來的結果沒法辦解析,網上找了一圈之後說是讓你加一個xdb6.jar和xmlparserv2.jar,加完還是報錯,最終找到可以在資料庫層面將xmltype轉換長varchar2

select goods_name,(BUDGET_DATE_xml).getstringval() from test_data 
pivot xml (sum(budget_money) for budget_date in(select budget_date from  test_data));

  

此時覺得已經ok了,但是屁股還沒坐熱就出現了新問題,varchar2最長4000,月份過多時會出現緩衝池記憶體不足的問題。這時心想可不可以轉成colb這樣就不會有問題了,抱著僥倖心理試了下getclobval,沒想到還真有這方法!

select goods_name,(BUDGET_DATE_xml).getclobval() from test_data 
pivot xml (sum(budget_money) for budget_date in(select budget_date from  test_data));

  

至此,問題得到解決,如大神還有其他處理方法,歡迎在評論區留言,小弟願聞其詳。