使用 PIVOT 函数的行到列 (Oracle)
Posted
技术标签:
【中文标题】使用 PIVOT 函数的行到列 (Oracle)【英文标题】:Rows to columns using PIVOT function (Oracle) 【发布时间】:2020-10-16 13:41:17 【问题描述】:我正在尝试创建一个查询以使用 PIVOT 函数将行转换为列。我有一个这种形式的表格(这只是部分视图,表格包含30多列)。
ID SUBJECT GRADE
000442 WRI001 C-
000442 PHY104 C
000442 MTH111 B
000442 MTH111 W
000442 MTH111 W
000442 PHY104 W
预期结果:
ID 'WRI001' 'MTH111' 'PHY104'
000442 C- B,W,W C,W
使用的查询:
select * from (
select ID,
SUBJECT,GRADE
from SECOND_YEAR_COMP
)
pivot
(
MAX(GRADE)
for SUBJECT in
('MTH111',
'WRI001',
'PHY104')
);
查询输出:
ID 'WRI001' 'MTH111' 'PHY104'
000442 C- W W
我知道,因为 MAX(GRADE),我每门科目的成绩都只有一个。有什么办法可以得到该科目的所有成绩(正如我上面给出的预期结果)。
【问题讨论】:
您显示的输出不是查询的输出。这是因为输出中的列将完全遵循 PIVOT 子句的 IN 列表中的顺序(除非您在查询末尾有 ORDER BY,而您没有)。 【参考方案1】:您可以使用listagg()
和条件聚合:
select id,
listagg(case when subject = 'WRI001' then grade end) WRI001,
listagg(case when subject = 'WRI001' then grade end) WRI001,
listagg(case when subject = 'PHY104' then grade end) PHY104
from second_year_comp
group by id
您可以使用within group
子句控制成绩在连接字符串中出现的顺序。假设你想按等级排序,那么:
select id,
listagg(case when subject = 'WRI001' then grade end) within group(order by grade) WRI001,
listagg(case when subject = 'WRI001' then grade end) within group(order by grade) WRI001,
listagg(case when subject = 'PHY104' then grade end) within group(order by grade) PHY104
from second_year_comp
group by id
【讨论】:
这是正确的 - 但既然 OP 已经在使用 PIVOT 运算符,为什么不在 PIVOT 中使用 LISTAGG 显示解决方案?【参考方案2】:您快完成了 - 唯一缺少的一点是 - 您应该使用 PIVOT
子句中的完整语法将 MAX
聚合函数替换为 LISTAGG
函数。
此外,我调整了数据透视列的名称以获得不错的名称(不带撇号)。
请看下面的例子:
select * from (
select ID,
SUBJECT,GRADE
from tab
)
pivot
(
LISTAGG(GRADE,',') within group (order by GRADE)
for SUBJECT in
('MTH111' as MTH111,
'WRI001' as WRI001,
'PHY104' as PHY104)
)
结果符合预期
ID MTH111 WRI001 PHY104
------ ---------- ---------- ----------
000442 B,W,W C- C,W
【讨论】:
几乎和预期的一样; OP 显示了不同的输出(正如我在他的问题下方的评论中解释的那样,这不是他与我们共享的查询的输出)。与输出中的列顺序有关 - 与 PIVOT 的 IN 列表中的顺序相同。【参考方案3】:您可以使用listagg()
进行字符串聚合,然后应用pivot
With cte as
(
SELECT ID, SUBJECT,LISTAGG(GRADE, ',') WITHIN GROUP (ORDER BY grade) AS grade
FROM tablename
GROUP BY id,SUBJECT
)
select * from (
select ID,SUBJECT,GRADE from cte)
pivot
(
MAX(GRADE)
for SUBJECT in ('MTH111','WRI001','PHY104')
);
【讨论】:
为什么聚合与透视分开?两者都是聚合操作; PIVOT 可以很好地处理 LISTAGG 作为聚合函数。我认为这不是一个好的答案(反映在投票中)。以上是关于使用 PIVOT 函数的行到列 (Oracle)的主要内容,如果未能解决你的问题,请参考以下文章