Oracle中行列轉換兩種實現(xiàn)方法
前言
行列轉換是指將行數(shù)據(jù)轉換為列數(shù)據(jù),或將列數(shù)據(jù)轉換為行數(shù)據(jù)的過程。這通常使用的辦法是用PIVOT和UNPIVOT函數(shù)來實現(xiàn)。這里描述兩種方法分別實現(xiàn)行列轉換?。?!
首先創(chuàng)建表:
學生表:student;--包括學生號,姓名,年紀,性別,生日
教師表:teacher;--包括教師編號,姓名
課程表:course;--包括課程編號,課程名稱,對應教師
學生成績表:sc;--包括學生號,課程編號,成績
創(chuàng)建表的腳本如下:
--學生 student表 drop table student; create table student( sno varchar2(10) primary key, sname varchar2(20), sage number(2), ssex varchar2(5), birthday date ); --教師 teacher表 drop table teacher; create table teacher( tno varchar2(10) primary key, tname varchar2(20) ); --課程 course表 drop table course; create table course( cno varchar2(10), cname varchar2(20), tno varchar2(20), constraint pk_course primary key (cno,tno) ); --學生成績 sc表 drop table sc; create table sc( sno varchar2(10), cno varchar2(10), score number(4,2), constraint pk_sc primary key (sno,cno) ); /*******初始化學生表的數(shù)據(jù)******/ insert into student values ('s001','張亍卬',FLOOR(months_between(SYSDATE,date '2000-3-5')/12),'男',date '2000-3-5'); insert into student values ('s002','李殳戔',FLOOR(months_between(SYSDATE,date '2001-2-3')/12),'男',date '2001-2-3'); insert into student values ('s003','吳仝玓',FLOOR(months_between(SYSDATE,date '2002-5-8')/12),'男',date '2002-5-8'); insert into student values ('s004','琴甪',FLOOR(months_between(SYSDATE,date '2000-6-15')/12),'女',date '2000-6-15'); insert into student values ('s005','王讱纊',FLOOR(months_between(SYSDATE,date '2000-8-12')/12),'女',date '2000-8-12'); insert into student values ('s006','李孖伣',FLOOR(months_between(SYSDATE,date '2001-9-20')/12),'男',date '2001-9-20'); insert into student values ('s007','劉辿吒',FLOOR(months_between(SYSDATE,date '2002-10-5')/12),'男',date '2002-10-5'); insert into student values ('s008','蕭竦俐',FLOOR(months_between(SYSDATE,date '2003-6-1')/12),'女',date '2003-6-1'); insert into student values ('s009','陳閆邠邡',FLOOR(months_between(SYSDATE,date '2001-1-15')/12),'女',date '2001-1-15'); insert into student values ('s010','陳芃伋',FLOOR(months_between(SYSDATE,date '2001-1-9')/12),'女',date '2001-1-9'); commit; /******************初始化教師表***********************/ insert into teacher values ('t001', '龔陽'); insert into teacher values ('t002', '諶燕'); insert into teacher values ('t003', '武明星'); commit; /***************初始化課程表****************************/ insert into course values ('c001','J2SE','t002'); insert into course values ('c002','Java Web','t001'); insert into course values ('c003','SSH','t001'); insert into course values ('c004','Oracle','t001'); insert into course values ('c005','SQL SERVER 2005','t003'); insert into course values ('c006','C#','t003'); insert into course values ('c007','JavaScript','t003'); insert into course values ('c008','DIV+CSS','t001'); insert into course values ('c009','PHP','t003'); insert into course values ('c010','EJB3.0','t002'); commit; /***************初始化成績表***********************/ insert into sc values ('s001','c001',78); insert into sc values ('s002','c001',80); insert into sc values ('s003','c001',81); insert into sc values ('s004','c001',60); insert into sc values ('s001','c002',82); insert into sc values ('s002','c002',72); insert into sc values ('s003','c002',81); insert into sc values ('s001','c007',88); insert into sc values ('s001','c010',73); insert into sc values ('s002','c003',69); insert into sc values ('s002','c008',92); insert into sc values ('s002','c009',81); insert into sc values ('s002','c007',85); insert into sc values ('s002','c010',75); insert into sc values ('s005','c001',63); insert into sc values ('s005','c002',96); insert into sc values ('s005','c007',75); insert into sc values ('s005','c010',72); insert into sc values ('s006','c001',72); insert into sc values ('s007','c001',61); insert into sc values ('s008','c001',92); insert into sc values ('s009','c001',58); insert into sc values ('s010','c001',85); insert into sc values ('s002','c004',80); insert into sc values ('s002','c005',70); insert into sc values ('s002','c006',60); commit;
一、行轉列(一)
使用case when/decode+聚合函數(shù)+group by的方法實現(xiàn)行轉列;
把sc表進行行轉列查詢出每個學生每門課程的成績:
原sc表:
SELECT * FROM sc;--學生成績表
執(zhí)行結果展示其中一部分:
此時要對cno課程編號進行行轉列:
select sno,sum(case cno when 'c001' then score end) c001, sum(case cno when 'c002' then score end) c002, sum(case cno when 'c003' then score end) c003, sum(case cno when 'c004' then score end) c004, sum(case cno when 'c005' then score end) c005, sum(case cno when 'c006' then score end) c006, sum(case cno when 'c007' then score end) c007, sum(case cno when 'c008' then score end) c008, sum(case cno when 'c009' then score end) c009, sum(case cno when 'c0010' then score end) c0010 from sc group by sno order by sno;
執(zhí)行結果:
展示的為每個學生他的每一門課程成績;
總結:
要求把查詢的哪一列轉成列名就放在case后面,并把它的列中值進行分類放在when后面;
比如學生成績表總共就三列(學生號,課程編號,學生成績),我們要查詢每個學生的每科成績展示,就需要對課程編號cno進行分類轉換,因此把課程編號cno放在case后面,然后把課程編號cno中所包含的所有值進行分類,即全部課程科目c001--c0010,分類放在when的后面!!
要把哪一列內容放在列中值中就放在then 后面;
意思就是我們最后要看的結果值,比如對應上面查詢,要查看的是學生成績score,此時就把學生成績score放在then的后面即可。
這種辦法可以實現(xiàn)我們對需求的解決實現(xiàn),但是使用比較麻煩,可能會理解錯誤,而且代碼語句寫的比較多,因此可以換種方法來更簡單實現(xiàn)行轉列?。?!
二、行轉列(二)
使用PIVOT函數(shù),可以將行數(shù)據(jù)轉換為列數(shù)據(jù),并且可以在同一查詢中匯總和篩選數(shù)據(jù)。
基本語法格式如下:
PIVOT(被聚合的列 FOR 行轉列的列 in(列中值1,列中值2...)) select * from 表 pivot (聚合函數(shù)(被聚合的列) for 行轉列的列 in (列中值1,,列中值2植..))
批注:
被聚合的列:變成列中值的列;
行轉列的列:由列中值變?yōu)榱忻牧?;
列中值1,列中值2..:新增加的列名(即為行轉列的列中的列中值)就是列中值1,列中值2...。
備注:被聚合的列要加聚合函數(shù)。
或者另一種理解:
SELECT * FROM (SELECT column1, column2, column3 FROM table_name) PIVOT (aggregate_function(column2) FOR column1 IN ('value1' AS alias1, 'value2' AS alias2, ...));
其中,PIVOT中的column1是要轉換為列的列,column2是要匯總的列,alias是列的別名。
那么此時“把sc表行轉列查詢每個學生每門課程的成績”可寫為:
select * from sc pivot(sum(score) for cno in('c001' c001,'c002' c002,'c003' c003,'c004' c004, 'c005' c005,'c006' c006,'c007' c007,'c008' c008,'c009' c009,'c010' c010)) order by sno;
其中,as可加可不加,對于列中值一定要加單引號。同時運行結果是和之前的一致。如圖所示:
使用PIVOT函數(shù)時,需要注意以下幾點:
- PIVOT函數(shù)必須在FROM子句中使用,因此需要將原始查詢包裝在一個子查詢中。
- aggregate_function是要應用于column2的聚合函數(shù),可以是SUM、AVG、COUNT、MAX、MIN等。
- FOR子句指定要在新列中顯示的值。在IN子句中指定這些值,并在別名中指定新列的名稱。
三、列轉行(一)
使用union all方法實現(xiàn)列轉行;
比如:有一張員工表emp,請用一條sql顯示如下格式
ENPNO KEY VALUE
7369 ENAME SMITH
7369 JOB CLERK
7369 MGR 7902
先看原員工表格式:
select * from emp;
通過對比發(fā)現(xiàn)是將原表中的列和其對應值轉換為行式展現(xiàn),同時為其定義了新的列名分別為ENPNO 、KEY 、VALUE 。那么用union all的方式實現(xiàn)的語句為:
select * from (select empno,'ENAME' KEY,ENAME VALUE FROM EMP UNION ALL select empno,'JOB' KEY,TO_CHAR(JOB) VALUE FROM EMP UNION ALL select empno,'MGR' KEY,TO_CHAR(MGR) VALUE FROM EMP UNION ALL select empno,'HIREDATE' KEY,TO_CHAR(HIREDATE) VALUE FROM EMP UNION ALL select empno,'SAL' KEY,TO_CHAR(SAL) VALUE FROM EMP UNION ALL select empno,'COMM' KEY,TO_CHAR(COMM) VALUE FROM EMP UNION ALL select empno,'DEPTNO' KEY,TO_CHAR(DEPTNO) VALUE FROM EMP) WHERE EMPNO=7369;
簡單理解為:查詢該員工編號對應的每一條列信息,對列中值進行格式轉換統(tǒng)一,然后使用union all進行并集為一個數(shù)據(jù)集合作為參考表,最后加判斷條件完成列轉換。那么看下這種方式的運行結果:
通過改圖發(fā)現(xiàn)確實已經(jīng)完成了目的需求的格式轉換。不過此方法同樣比較繁瑣,代碼量也比較多,所以可以換另外一種方法實現(xiàn)同樣的效果。
四、列轉行(二)
UNPIVOT函數(shù)可以將列數(shù)據(jù)轉換為行數(shù)據(jù)?;菊Z法如下:
unpivot 列轉行自動去空 如果要留住空值 在unpivot 后加上 include nulls
unpivot(被聚合的列的新列名 for 列轉行的列的新列名 in (字段1,字段2...))
被聚合的列的新列名:指的是目標結果集的列名,按照目標結果集來填寫,即原來聚合的數(shù)據(jù)如這里的nums,列轉行之前的列中值放在取了新名字的這個列中;
列轉行的列的新列名:指的是要列轉行的列名的集合新名字,既創(chuàng)建一個新的列來存儲要列轉行的列,如這里的name,他的列中值在列傳行之前為原視圖的多個列;
字段1,字段2...:指的是要列轉行的列名,既為要放到列轉行的列的新列名里的列中值,就是列轉行之前視圖的多個列。
完整格式:
SELECT * FROM table_name UNPIVOT (column3 FOR column1 IN (column2, column3, ...));
column1是要轉換為行的列,column2和column3是要轉換的列。
那么此時使用UNPIVOT函數(shù)完成上個問題的列轉行方法就可以寫為:
select * from (SELECT empno,ENAME,JOB, TO_CHAR(MGR) MGR, TO_CHAR(HIREDATE) HIREDATE, TO_CHAR(SAL) SAL, TO_CHAR(COMM) COMM, TO_CHAR(DEPTNO) DEPTNO FROM EMP WHERE EMPNO=7369) unpivot include nulls(VALUE for KEY IN(ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO));
這里在列轉行時對表中每一列做了格式統(tǒng)一,最后運行結果和第一種方法一樣。如圖所示:
使用UNPIVOT函數(shù)時,需要注意以下幾點:
- UNPIVOT函數(shù)必須在FROM子句中使用,因此需要將原始查詢包裝在一個子查詢中。
- FOR子句指定要轉換為行的列。
- IN子句指定要轉換的列。
總結
到此這篇關于Oracle中行列轉換兩種實現(xiàn)方法的文章就介紹到這了,更多相關Oracle行列轉換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
PLSQL Developer連接Oracle11g 64位數(shù)據(jù)庫配置詳解(圖文)
這篇文章主要介紹了PLSQL Developer連接Oracle11g 64位數(shù)據(jù)庫配置詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09Oracle數(shù)據(jù)庫如何使用exp和imp方式導數(shù)據(jù)
在平時的工作中,我們難免會遇到要備份數(shù)據(jù),當然用pl/sql可以實現(xiàn)通過導出數(shù)據(jù)來備份數(shù)據(jù),下面這篇文章主要給大家介紹了關于Oracle數(shù)據(jù)庫如何使用exp和imp方式導數(shù)據(jù)的相關資料,需要的朋友可以參考下2022-06-06Oracle 數(shù)據(jù)庫 臨時數(shù)據(jù)的處理方法
在Oracle數(shù)據(jù)庫中進行排序、分組匯總、索引等到作時,會產(chǎn)生很多的臨時數(shù)據(jù)。如有一張員工信息表,數(shù)據(jù)庫中是安裝記錄建立的時間來保存的。2009-06-06oracle數(shù)據(jù)庫添加或刪除一列的sql語句
需要注意的一點,如果要修改的表,不是當前的用戶的表,那么就需要添加上用戶的名稱。以及有修改此表的權限2012-05-05生產(chǎn)環(huán)境Oracle undo表空間管理實踐
這篇文章主要介紹了生產(chǎn)環(huán)境Oracle undo表空間管理實踐,Oracle 數(shù)據(jù)庫有一種維護信息的方法,用于回滾或撤消對數(shù)據(jù)庫的更改,下面文章分享更多的相關資料需要的小伙伴可以參考一下2022-03-03