Oracle10G SQL:将列转换为行

时间:2012-07-25 06:14:55

标签: sql oracle

我需要将列转换为行并获得平均值。

例如我有这张表:

Name   Math    Science     Computer
----   ----    -------     --------
Ted    90       89          95
Zed    99       98          98
Fed    85       75          90

输出应为:

Subject      Average
-------      -------
Math         88
Science      87.33
Computer     94.33

我怎样才能实现它?谢谢你的帮助。

1 个答案:

答案 0 :(得分:2)

如果您使用的是11G,则可以使用unpivot

SELECT subject, AVG(percentage) AS percentage
FROM (
    SELECT * FROM tablea
    UNPIVOT (percentage FOR subject IN (math, science, computer))
)
GROUP BY subject
ORDER BY subject;

SUBJECT  PERCENTAGE
-------- ----------
COMPUTER      94.33
MATH          91.33
SCIENCE       87.33

但既然你不是,那你可以假装它。适应this site

SELECT subject, AVG(percentage) AS percentage
FROM (
    SELECT DECODE(unpivot_row, 1, 'Math',
                               2, 'Science',
                               3, 'Computer') AS subject,
           DECODE(unpivot_row, 1, math,
                               2, science,
                               3, computer) AS percentage
    FROM tablea
    CROSS JOIN (SELECT level AS unpivot_row FROM dual CONNECT BY level <= 3)
)
GROUP BY subject
ORDER BY subject;

SUBJECT  PERCENTAGE
-------- ----------
Computer      94.33
Math          91.33
Science       87.33

在这两种情况下,内部select正在将行转换为列;在10克你只需要自己做。 SELECT ... CONNECT BY ...只生成一个虚拟值列表,这必须足以覆盖您要转换为行的列数(如果您确实有1000个,则应该重新访问数据模型)。两个decode语句使用生成的数字来匹配列名和值 - 单独运行内部选择以查看它的外观。

不依赖于动态SQL,你无法摆脱列表 - 只有一次使用真实的unpivot,而是两次使用假的10g版本,你必须确保它们匹配正确,并且行号生成器正在生成足够的值。 (太多了,你可能会得到奇怪的结果,但是因为任何额外的值在这里都是null而你正在使用avg,在这种情况下它并不重要;只是作为一个完整性检查你应该做的它完全匹配。)


或者是另一个版本,基于您总是想要除name之外的所有列,这意味着您只需要列出您想要的列一次,并且更容易在视觉上匹配它们 - 只需继续添加{{1条款;而且你不需要行数:

when