如果您使用的是 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
但既然你不是,你可以假装它。改编自本网站:
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
都将行转换为列;在 10g 中你只需要自己做。只是生成一个虚拟值列表,这SELECT ... CONNECT BY ...
必须足以涵盖要转换为行的列数(如果你真的有 1000 个,你应该重新审视数据模型)。这两个decode
语句使用生成的数字来匹配列名和值 - 自行运行内部选择以查看其外观。
如果不使用动态 SQL,您将无法避免列出列 - 只列出一次真实unpivot
的 10g 版本,但两次使用假的 10g 版本,并且您必须确保它们正确匹配,并且行号生成器正在产生足够的价值。(太多了,你可能会得到奇怪的结果,但是由于任何额外的值在这里都是 null 并且你正在使用avg
,在这种情况下它并不重要;就像一个健全性检查一样,你应该让它完全匹配) .
或者另一个版本,基于你总是想要除 之外的所有列name
,这意味着你只需要列出你想要的列一次,并且更容易在视觉上匹配它们 - 只需继续添加when
子句;而且您不需要行数:
SELECT subject, AVG(percentage) AS percentage
FROM (
SELECT column_name AS subject,
CASE
WHEN column_name = 'MATH' then math
WHEN column_name = 'SCIENCE' then science
WHEN column_name = 'COMPUTER' then computer
END AS percentage
FROM tablea
CROSS JOIN (
SELECT column_name
FROM user_tab_columns
WHERE table_name = 'TABLEA'
AND column_name != 'NAME'
)
)
GROUP BY subject
ORDER BY subject;
SUBJECT PERCENTAGE
------------------------------ ----------
COMPUTER 94.33
MATH 91.33
SCIENCE 87.33