Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Oracle10G SQL:transformando colunas em linhas


Se você estivesse em 11G, poderia usar 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

Mas como você não é, você pode fingir. Adaptação de deste 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

Em ambos os casos, o select interno está transformando linhas em colunas; em 10g você só tem que fazer você mesmo. O SELECT ... CONNECT BY ... apenas gera uma lista de valores fictícios, e isso deve ter o suficiente para cobrir o número de colunas que você está convertendo em linhas (e se você realmente tiver 1000, deve realmente revisitar o modelo de dados). Os dois decode As instruções usam esse número gerado para corresponder a um nome e valor de coluna - execute a seleção interna por conta própria para ver como é.

Sem recorrer ao SQL dinâmico, você não pode deixar de listar as colunas - apenas uma vez com o unpivot real , mas duas vezes com a versão 10g falsa, e você precisa ter certeza de que eles correspondem corretamente e que o gerador de números de linha está produzindo valores suficientes. (Muitos e você pode obter resultados estranhos, mas como qualquer valor extra será nulo aqui e você está usando avg , não importa muito neste caso; apenas como uma verificação de sanidade, você provavelmente deve fazer com que corresponda exatamente de qualquer maneira).

Ou outra versão, com base em você sempre querendo todas as colunas, exceto name , o que significa que você só precisa listar as colunas que deseja uma vez e é mais fácil combiná-las visualmente - continue adicionando when cláusulas; e você não precisa da contagem de linhas:
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