摘要:(简要介绍Oracle11g SQL的新功能 pivot/unpivot 的使用方法以及如何使用它们做到行列转换.
蓄势以久的Oracle 11g 终于七月敲锣打鼓隆重推出,接下来就是网上漫天盖地的新功能介绍。11g面向开发的新功能本来就不多,掰着手指头也就是pivot和查询结果缓存的新Hint。本以为不久就会有人详述,谁知盼到两眼欲穿,大家还是翻来覆去的讨论DBA的自动分区之类。Oracle自己的门脸上到是每每用客气的冷漠写着“马上就来” (coming soon),可这马上都转眼都快马上了一个月了,还迟迟不见盖头掀起来。
(http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/index.html?rssid=rss_otn_articles)
伟人说过“自己动手,丰衣足食”,等不来,咱就自己来。没吃过猪肉,还没见过猪跑?说干就干,下载安装再加一本“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
写这个SQL的技巧就是按姓名分组,然后使每一组每一类的电话号码最多只有一个,里边用到的分组函数都是聋子的耳朵-摆设。用MAX可以,MIN也行。
这个查询写出来就是:
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">10</column><column name = "SUM(SAL)">8750</column></item><item><column name = "DEPTNO">20</column><column name = "SUM(SAL)">10875</column></item><item><column name = "DEPTNO">30</column><column name = "SUM(SAL)">9400</column></item></PivotSet>
这个东西的结果具体怎么用就留给大家做作业了。反正XML咱也不熟,借这个机会就下了。。。(注:此文为转载)
分享到:
相关推荐
在Oracle数据库中,行转列(也称为数据透视)和列转行(unpivot)是SQL查询中用于数据转换的高级功能。从Oracle 11g版本开始,引入了PIVOT和UNPIVOT关键字,以支持显式的查询转换,即从行数据转换为列数据,或从列...
- T-SQL_经典行专列、列转行,分页及存储过程.doc:T-SQL是SQL Server的扩展,但其中的行转列和分页概念与Oracle相似。在Oracle中,可以使用ROW_NUMBER()函数配合PARTITION BY和ORDER BY来实现分页查询。 - oracle_...
列转行(Pivot)和行转列(Unpivot)是两种基本操作,可以将数据按照不同的维度进行组织。传统的列转行方法通常涉及`DECODE`或`CASE`函数与聚合函数如`MAX`或`MIN`的结合,但这些方法可能在处理大量数据时对性能造成...
在Oracle数据库管理中,数据处理有时需要将行数据转换为列数据,或者将列数据转换为行数据,这种操作被称为行列转换。Oracle 10g 提供了多种方法来实现这种转换,包括使用PIVOT和UNPIVOT操作,以及自定义SQL查询等。...
然而,需要注意的是,WM_CONCAT并不是Oracle官方提供的标准函数,它在Oracle 11g R2版本之后就被标记为不推荐使用,因为它的性能和可扩展性有限。尽管如此,在早期版本中,WM_CONCAT仍然被广泛使用。 WM_CONCAT函数...
本篇文章将详细讲解Oracle 10g中的行列转换技术,包括如何实现行转列和列转行。 首先,我们要了解为什么要进行行列转换。在实际业务场景中,有时我们需要将多行数据合并到一列,或者将一列数据分散到多行,以适应...
- **PIVOT**:Oracle 11g引入的新特性,允许更方便地进行行转列操作。例如,如果要将`t_row_col`中的行转为列,可以使用PIVOT: ```sql SELECT * FROM t_row_col PIVOT ( MAX(cv) FOR cn IN ('c1', 'c2', 'c3') )...
而在Oracle 11g及更高版本,引入了`PIVOT`功能,使得行转列更加直观。`PIVOT`语句允许指定列名和对应的值,生成新的列。 - **列转行**:列转行通常需要使用`UNION ALL`或`UNPIVOT`操作。`UNPIVOT`可以把多列数据...
#### 二、列转行 **2.1 使用 UNION ALL 实现列转行** 适用于Oracle 8i、9i、10g及以上版本。 - **步骤与示例**: - 首先创建一个表`t_col_row`,包含三列`c1`、`c2`、`c3`。 - 插入几条记录,其中部分记录包含...
Oracle 10g数据库应用之ADO数据访问技术是数据库编程中的一个重要主题,尤其对于使用Visual Basic等编程语言的开发者来说。ADO(ActiveX Data Objects)是一种流行的数据访问接口,允许程序与各种数据库进行交互,...
列转行是指将表中的多列数据转换为单列多行的形式。这一操作在某些分析场景下非常有用,例如,当你需要展示每个记录的不同属性时。 **1. UNION ALL 方法** - **适用版本**: Oracle 8i 及以上 - **操作原理**: ...
在这个例子中,通过使用`DECODE`函数配合子查询中的`ROWNUM`实现了行转列的功能。 ##### 2. 列转行 对于列转行的需求,可以通过窗口函数实现,如下所示: ```sql -- 创建示例表 CREATE TABLE t (col1 VARCHAR2(10),...
根据给定的部分内容,我们可以通过三种不同的方法来进行列转行操作。 ##### 2.1 使用 UNION ALL 进行列转行 适用于 Oracle 数据库 8i 及以上版本。这种方法的基本思路是将每列作为独立的查询结果,然后使用 `UNION...
这种转换通常分为两大类:列转行与行转列。除此之外,还会涉及将多列或多行的数据合并为字符串,或将字符串拆分为多列或多行等操作。本文将重点探讨如何通过SQL语句实现这些转换,特别是将多行数据转换为单一字符串...