Oracle
 sql >> Database >  >> RDS >> Oracle

Oracle10G SQL:trasformare le colonne in righe

Se eri su 11G potresti usare 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

Ma dato che non lo sei, puoi fingere. Adattamento da questo sito :

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

In entrambi i casi, il select interno sta trasformando le righe in colonne; in 10 g devi solo farlo da solo. Il SELECT ... CONNECT BY ... genera solo un elenco di valori fittizi e questo deve avere abbastanza per coprire il numero di colonne che stai convertendo in righe (e se ne hai davvero 1000, dovresti davvero rivisitare il modello di dati). I due decode le istruzioni utilizzano quel numero generato per abbinare il nome e il valore di una colonna:esegui la selezione interna da sola per vedere come appare.

Senza ricorrere all'SQL dinamico, non puoi evitare di dover elencare le colonne - solo una volta con il vero unpivot , ma due volte con la versione falsa da 10 g, e devi assicurarti che corrispondano correttamente e che il generatore di numeri di riga stia producendo valori sufficienti. (Troppi e potresti ottenere risultati strani, ma poiché tutti i valori extra saranno nulli qui e stai usando avg , non importa molto in questo caso; proprio come un controllo di integrità dovresti probabilmente farlo corrispondere esattamente comunque).

O un'altra versione, in base al fatto che desideri sempre tutte le colonne tranne name , il che significa che devi elencare le colonne che desideri solo una volta ed è più facile abbinarle visivamente:continua ad aggiungere when clausole; e non hai bisogno del conteggio delle righe:

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