oracle 11g 使用 pivot/unpivot 行列轉換
轉自 http://tech.it168.com/db/2007-09-07/200709071114985.shtml
【IT168技術文件】
摘要:(簡要介紹Oracle11g SQL的新功能 pivot/unpivot 的使用方法以及如何使用它們做到行列轉換.
蓄勢以久的Oracle 11g 終於七月敲鑼打鼓隆重推出,接下來就是網上漫天蓋地的新功能介紹。11g面向開發的新功能本來就不多,掰著手指頭也就是pivot和查詢結果快取的新Hint。本以為不久就會有人詳述,誰知盼到兩眼欲穿,大家還是翻來覆去的討論DBA的自動分割槽之類。Oracle自己的門臉上到是每每用客氣的冷漠寫著“馬上就來” (coming soon),可這馬上都轉眼都快馬上了一個月了,還遲遲不見蓋頭掀起來。
()
偉人說過“自己動手,豐衣足食”,等不來,我們就自己來。沒吃過豬肉,還沒見過豬跑?說幹就幹,下載安裝再加一本“SQL參考手冊”,齊了。這新花活到底怎麼使,且聽我從頭道來。。。
1. 11g以前的行列轉換
領袖又說了:“溫故而知新”。那就讓我們先看看11g以前是怎麼實現地。行列轉換一直當作甄別老手和新手的試金石,面試的時候面試官不問這個都不好意思張嘴。Itpub的Oracle開發版更是每隔十天半個月就有人問這個,你說重要不重要。
假設有表emp_phone如下:
NAME | TYPE | PHONE |
張三 | 1 | 1234-5678 |
張三 | 2 | 4567-7890 |
張三 | 3 | 6000-1001 |
李四 | 1 | 2123-1237 |
李四 | 3 | 6001-5600 |
馬五u | 1 | 3248-1378 |
馬五 | 2 | 3423-3948 |
王二(沒麻子) | 2 | 2890-1245 |
。。。 |
表裡放著張三李四王二麻子等等主人翁的電話號碼。(TYPE 1/2/3分別對應家/辦公室/手機)。如果要把每個人的所有電話放在一行上,就是行轉列了。結果如下:
NAME | HOME | OFFICE | MOBILE |
張三 | 1234-5678 | 4567-7890 | 6000-1001 |
李四 | 2123-1237 | 6001-5600 | |
馬五 | 3248-1378 | 3423-3948 | |
王二(沒麻子) | 2890-1245 |
這個查詢寫出來就是:
SELECT name, MAX(decode(type, 1, phone)) Home, MAX(decode(type, 2, phone)) Office, MAX(decode(type, 3, phone)) Mobile FROM emp_phone GROUP BY Name /
那位看官說了:“能不能再變回去?”能,不能戲法不就漏了不是?
這兒要用到另一的技巧就是笛卡爾乘積,將一行復製成三行,每一行取一個型別的電話
偷個懶兒把上邊的結果表叫emp_phone_x,把列還原成行的SQL:
SELECT NAME, DECODE (lvl, 1, home, 2, office, 3, mobile) phone FROM emp_phone_x, (SELECT LEVEL lvl FROM DUAL CONNECT BY LEVEL <= 3) WHERE DECODE (lvl, 1, home, 2, office, 3, mobile) IS NOT NULL /
轉來轉去,一來一往,陰陽辟易,詳推用意終何在,延年益壽不老春。往玄裡說,就是老祖宗老掛在嘴邊上的“道”。那位又說了:“這都哪兒跟哪兒啊?怎麼扯到太極拳上去了”。
2. 11g 自帶的行列轉換 旁邊那個帶眼鏡,說的就是你,眼珠子直勾勾的怎麼了?上面的沒看懂? 要是以前,我老先生就得語重心長地教育你,那麼重要的東西沒看懂,將來想不想換工作了?但現在這話就說不出口了,因為11g的SQL自己就帶這個了。
11g在SELECT語句中新加了關鍵詞PIVOT和UNPIVOT,用這兩個關鍵詞,重寫上面的兩個查詢,就變成這個樣子的了:
行變列:
SELECT * FROM emp_phone
PIVOT (
MAX(phone) for type IN (1 as home, 2 as office, 2 as mobile)
)
/
PIVOT以後的字句都是新加的。但萬變不離其宗,還是要用到分組函式。IN後邊是按type的不同值對映成不同的列。簡單吧?
列變行,這是UNPIVOT的工作,寫法如下:
SELECT * FROM emp_phone_x UNPIVOT ( phone FOR type in (HOME AS 1, OFFICE AS 2, MOBILE AS 3) ) / 這裡是把不同的列轉換成不同的type的數值。 再用SCOTT使用者裡的EMP表做個例子,列出各部門之間工資總和: SELECT * FROM ( (SELECT sal, deptno FROM emp) PIVOT ( SUM(sal) FOR deptno IN (10 as dept_10, 20 as dept_20, 30 as dept_30) ) ) / DEPT_10 DEPT_20 DEPT_30 ---------- ---------- ---------- 8750 10875 9400
再往深裡想,前邊的所有例子都有一個侷限,電話的type和emp的deptno都是有限的、可窮舉的。如果這些列都是可隨時可新增的,又該怎麼辦呢?11g以前肯定是要動用動態SQL的法寶。那11g又是怎麼處理的呢?剛看SQL參考手冊的時候,看到裡邊豁然寫著IN後邊可以接子查詢或ANY,當時是佩服的眼淚嘩嘩的,迫不及待趕緊試一試:
SELECT * FROM ( (SELECT sal, deptno FROM emp) PIVOT ( SUM(sal) FOR deptno IN (SELECT deptno FROM dept) ) ) / ERROR at line 5: ORA-00936: missing expression SELECT * FROM ( (SELECT sal, deptno FROM emp) PIVOT ( SUM(sal) FOR deptno IN (ANY) ) ) / ERROR at line 5: ORA-00936: missing expression
這一下又變成拔涼拔涼的,這麼大個ORACLE也不能無恥到這個地步吧?正準備再確認一下手冊,抓他個人贓俱獲,突然有發現裡邊豁然寫著:
A subquery is used only in conjunction with the XML keyword… The ANY keyword is used only in conjunction with the XML keyword… 學習不認真,該打。原來是給生成XML串用的,正確用法如下: SELECT * FROM ( (SELECT sal, deptno FROM emp) PIVOT XML ( SUM(sal) FOR deptno IN (ANY) ) ) <PivotSet><item><column name = "DEPTNO">10column>
<column name = "SUM(SAL)">8750column>item><item>
<column name = "DEPTNO">20column><column name = "SUM(SAL)">10875column>item><item>
<column name = "DEPTNO">30column><column name = "SUM(SAL)">9400column>item>PivotSet>
這個東西的結果具體怎麼用就留給大家做作業了。反正XML我們也不熟,借這個機會就下了。。。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/67798/viewspace-1042075/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- pivot、unpivot實現oracle行列轉換Oracle
- SQL Server中行列轉換 Pivot UnPivotSQLServer
- Spark實現行列轉換pivot和unpivotSpark
- SQL Server 2005之PIVOT/UNPIVOT行列轉換(轉)SQLServer
- Oracle行列轉換及pivot子句的用法Oracle
- oracle11g pivot 行列轉換 SQL Server 2005OracleSQLServer
- sql的行轉列(PIVOT)與列轉行(UNPIVOT)SQL
- sql pivot、unpivot和partition by用法SQL
- Oracle-行列轉換Oracle
- Oracle 11g使用UNPIVOT函式實現“列轉行”Oracle函式
- oracle行列轉換-行轉列Oracle
- oracle行列轉換-列轉行Oracle
- oracle行列轉換-多行轉換成字串Oracle字串
- Oracle 行列轉換 經典Oracle
- Oracle 行列轉換總結Oracle
- Oracle 行列轉換小結Oracle
- Oracle行列轉換總結Oracle
- oracle行列轉換-字串轉換成多列Oracle字串
- oracle行列轉換-多列轉換成字串Oracle字串
- oracle和mysql的行列轉換OracleMySql
- 行列轉換
- Oracle--SQL行列轉換實戰OracleSQL
- Oracle 11g Pivot函式實現行轉列Oracle函式
- 使用Oracle 11g函式Pivot實現資料聚合行轉列Oracle函式
- Kettle行列轉換
- 偽行列轉換!
- 行列轉換sqlSQL
- 使用sed做特殊的行列轉換
- 行列轉換 交叉表 (轉)
- 用ORACLE分析函式實現行列轉換Oracle函式
- MySQL行列轉換拼接MySql
- 行列轉換之大全~~~
- sql server 行列轉換SQLServer
- 試驗Oracle中實現行列轉換的方法(轉)Oracle
- 行列轉換,列行轉換統計
- Oracle行列互換總結Oracle
- oracle 行列互換總結Oracle
- Oracle11新特性——行列轉換語句(二)Oracle