我需要将列转换为行并获取其平均值。
例如,我有此表:
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
我该如何实现?感谢您的帮助。
如果您使用的是11G,则可以使用unpivot:
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都将行转换为列。在10克中,您只需要自己做即可。在SELECT ... CONNECT BY ...刚刚产生虚值的列表,这必须有足够的覆盖要转换为行(如果你真的有1000,你真的应该重新审视数据模型)的列数。这两个decode语句使用生成的数字来匹配列名和值- 自行运行内部选择以查找外观。
select
SELECT ... CONNECT BY ...
decode
如果不采用动态SQL,就无法不必列出列- 只能使用real列出一次unpivot,而使用伪造的10g版本只能列出两次,并且必须确保它们正确匹配,并且必须确保行号生成器正在产生足够的价值。(太多,您可能会得到奇怪的结果,但是由于任何额外的值在此处都为null且您正在使用avg,因此在这种情况下并没有太大关系;就像健全性检查一样,您可能应该使其完全匹配) 。
avg
或另一个版本,根据您总是想要除之外的所有列name,这意味着您只需要列出您想要的列一次,并且在视觉上将它们匹配起来更容易- 只需添加when子句即可;并且您不需要行计数:
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