oracle 分析函數

Oracle 行列轉換函數

create table exam_record
(id integer primary key,
username varchar2(40),
classtype varchar2(40),
classname varchar2(200),
score number(20,2)
);
insert into exam_record values(1,'張三','文科','語文',97);
insert into exam_record values(2,'李四','理科','數學',80);
insert into exam_record values(3,'王五','理科','化學',90);
insert into exam_record values(4,'張三','文科','英語',88);
insert into exam_record values(5,'張三','理科','化學',92);
insert into exam_record values(6,'李四','理科','物理',70);
insert into exam_record values(7,'王五','文科','語文',67);
insert into exam_record values(8,'李四','文科','語文',100);
insert into exam_record values(9,'王五','文科','歷史',79);

select * from exam_record;

wKioL1k3lpewFlwtAAAo9EoCxfk999.png

1.  oracle行轉列(連接字符串函數)

  1. 方法一:wmsys.wm_concat(column)     

介紹:其函數在Oracle 10g推出,在10g版本中,返回字符串類型,在11g版本中返回clob類型。括號裏面的參數是列,而且可以是多個列的集合,也就是說在括號裏面可以自由地用‘||’合併字符串。如下面的例子:

selectusername,to_char(wmsys.wm_concat(classname||':'||score)) "成績單" from exam_record group by username;

 wKioL1k3lpjR_DjEAAAPdS1AVdM564.png

  1. 方法二:listagg(column,[,]) within group (order by ) [over (partition by  )]          

介紹:其函數在Oracle 11g 版本中推出,對分組後的數據按照一定的排序進行字符串連接。其中,“[,]”表示字符串連接的分隔符,如果選擇使用[over(partition by )]則會使其變成分析函數;

selectusername, listagg(classname||':'||score,';') within group (order by id desc)"成績單
" from exam_recordgroup by username;

wKiom1k3lpihECh6AAAPKlK3VZA543.png

  1. 方法三:sys_connect_by_path(column,<分隔符>)         

介紹:其函數在Oracle 9i 版本中推出,用來合併鏈路的字符串。注意的是其一定要和connect by子句合用!

第一個參數是形成樹形式的字段,第二個參數是父級和其子級分隔顯示用的分隔符。 

SELECT username,LTRIM(MAX(SYS_CONNECT_BY_PATH(classname||':'||score, '//')), '//') "成績單"  
FROM (SELECT classname, score , username,ROW_NUMBER() OVER(PARTITION BY username ORDER BY id DESC) RN  
          FROMexam_record)  
START WITH RN = 1 
CONNECT BY RN - 1 = PRIOR RN  
       ANDusername = PRIOR username  
GROUP BY username;

wKiom1k3lpmB71x8AAAQgD_8Ku8595.png


Oracle 11g中,Oracle 又增加了2個查詢:pivot(行轉列)unpivot(列轉行)

2. pivot 列轉行

語法規範:

SELECT ....FROM    PIVOT    (      aggregate-function()      FOR IN (‘’, ‘’,..., )        ) ASWHERE .....

注意: pivot(聚合函數for 列名 in(類型)),其中 in(‘’) 中可以指定別名,該行是必需的,因此不幸的是,您需要預先知道可能的值。該限制在 XML 格式的查詢將有所放寬(略。。。)

in中不可以指定子查詢,比如select distinct classnamefrom exam_record;

select *
  from (select username, classname, score
          from exam_record) pivot(max(score) 
               forclassname in ('語文' 語文, '數學' 數學, '英語' 英語, '物理' 物理, '化學' 化學, '歷史' 歷史, '生物' 生物)
         );

pivot(聚合函數 for 列名 in(類型),這裏的列名可以是多個,比如

pivot(max(score) for(classtype,classname) in (('文科','語文'), ('理科','數學'))
select *
  from (selectusername, classtype, classname, score
          fromexam_record) pivot ( max(score) for (classtype,classname) in (('文科','語文'),('理科','數學'))
         );

wKioL1k3lpnheMsnAAAL0gPqS1A937.png

pivot(聚合函數 for 列名 in(類型),這裏的聚合函數可以是多個,比如

select *
  from (selectusername, classtype,  score
          fromexam_record) pivot ( sum(score) sum_score,avg(score) avg_score  for (classtype) in (('文科'),('理科'))
         );

wKioL1k3lprTLSXdAAASfuJUh2Q865.png


3. unpivot 行轉列

unpivot 可以是 pivot 的反向操作,但不要以爲前者可以對後者所進行的任何操作進行反向操作。

create table user_scores  as 
select *
  from (selectusername, classname, score
          fromexam_record) pivot(max(score) 
              for classname in ('語文' 語文, '數學' 數學, '英語' 英語, '物理' 物理, '化學' 化學, '歷史' 歷史, '生物' 生物)
         );
         
select * from user_scores;


wKiom1k3lpuCxTK2AAARdcHhXCw949.png

 

select username, classname, score
  from user_scores unpivot(score for classnamein (語文, 數學, 英語, 物理, 化學, 歷史, 生物));

wKioL1k3lpuRLDkvAAAanc5XT2k056.png

XML類型

上述pivot列轉行示例中,你已經知道了需要查詢的類型有哪些,用in()的方式包含,假設如果您不知道都有哪些值,您怎麼構建查詢呢?

pivot 操作中的另一個子句 XML 可用於解決此問題。該子句允許您以XML 格式創建執行了 pivot 操作的輸出,在此輸出中,您可以指定一個特殊的子句 ANY 而非文字值

示例如下:

select *
  from (selectusername, classname, score from exam_record)       
       pivotxml(max(score) for classname in (any))
 order by 1 desc;

XML中也可以使用子查詢代替未知的列值

select *
  from (selectusername, classname, score from exam_record)       
       pivotxml(max(score) for classname in (select distinct classname from exam_record))
 order by 1 desc;


wKiom1k3lpzC5DH8AAALUztYoi8537.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章