Ако бяхте на 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 версия и трябва да се уверите, че съвпадат правилно и че генераторът на номера на редове произвежда достатъчно стойности. (Твърде много и може да получите странни резултати, но тъй като всички допълнителни стойности ще бъдат нулеви тук и използвате 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