Oracle语法:pivot和unpivot
PIVOT
pivot是一个在Oracle中输出EXCEL报表时非常有用的函数,它可以将字段值转成列名,并且同时做一些聚合操作。
语法
语法格式:pivot(聚合函数 for 需要转为列的字段名 in(需要转为列的字段值,可多个))
1 | SELECT * |
- aggregate_function:指定用于对value_column进行聚合操作的函数,如SUM、AVG等。(FOR关键字前面的部分只能使用聚合函数)
- value_column: 指定要聚合的源数据列。
- pivot_column: 指定要透视的列,其唯一值将被用作新列的列头。且源数据查询的select中必须包含这个字段,以便PIVOT函数可以使用到它。(可以理解为用这个字段来进行group by)
- value1 AS alias1, value2 AS alias2, …, valuen AS aliasn: 为透视列的每个唯一值指定一个别名,这些别名将成为新列的列头。遗憾的是这里不是使用子查询。
示例1
有一个产品销售表如下:
1 | CREATE TABLE PRODUCT_SELL |
插入测试数据:
如果我们要根据2018年各产品销售量给出各个月销售数量表,sql可以写成这样:
1 | SELECT * --这里只能用 “*” 号,或者没有进行转换的字段,比如这里的PRODUCT_NAME,而不能含有SELL_COUNT、MON这两个字段 |
sql执行的结果如下:
示例2
数据准备如下:
1 | CREATE TABLE sales_data ( |
比较如下两段SQL及查询结果:
1 | -- 以地区为行 商品为列 |
查询结果为:
1 | SELECT |
查询结果为:
可以看出,这段SQL是查询每个地区、每个月的商品销售额。和前一段SQL的不同之处,是查询的数据源是sales_data表,而不是这个 ( SELECT product_name, region, SALE_AMOUNT FROM sales_data ) 进行了字段选择的临时表,可以看出PIVOT实际上会用除 pivot_column 和 value_column 以外的字段组合当成唯一键(类似group by)进行分组统计。
示例3
数据准备如下:
如下sql语句(in中使用子查询):
1 | select * from T_Student_Grades |
报错提示:ORA-00936:缺失表达式。所以可以看出in不支持子查询。
UNPIVOT
UNPIVOT函数的功能和PIVOT相反,可以将多个列转为行。
语法
1 | SELECT * |
new_column_name:要转成行的列的值,转换后归属的新的列名。
column_to_unpivot:要转成行的列的名称,转换后归属的新的列名。
list_of_columns:要转成成行的列,组成的一个列表。
示例1
以下是一个示例,演示如何使用UNPIVOT函数实现列转行效果。
- 创建成绩表并插入数据:
1 | CREATE TABLE tscores ( |
- 使用UNPIVOT函数进行列转行操作:
1 | SELECT id, name, subject, score |
运行以上代码,将会得到以下结果:
| ID | NAME | SUBJECT | SCORE |
|---|---|---|---|
| 2 | Alice | Chinese | 95 |
| 2 | Alice | English | 90 |
| 2 | Alice | Math | 75 |
| 3 | Bob | Chinese | 85 |
| 3 | Bob | English | 80 |
| 3 | Bob | Math | 90 |
| 1 | John | Chinese | 90 |
| 1 | John | English | 85 |
| 1 | John | Math | 80 |
| 4 | Mary | Chinese | 92 |
| 4 | Mary | English | 95 |
| 4 | Mary | Math | 88 |
以上示例中,原始表scores包含了列chinese_score、math_score和english_score。通过UNPIVOT函数,将这些列转换为行,每行包含了学生的id、name、科目和成绩。最终查询结果显示了每位学生的不同科目成绩。