Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle10G SQL :Transformer les colonnes en lignes

Si vous étiez sur 11G, vous pourriez utiliser 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

Mais puisque vous ne l'êtes pas, vous pouvez faire semblant. Adaptation de ce 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

Dans les deux cas, le select intérieur transforme les lignes en colonnes ; en 10g vous n'avez qu'à le faire vous-même. Le SELECT ... CONNECT BY ... génère simplement une liste de valeurs factices, et cela doit en avoir assez pour couvrir le nombre de colonnes que vous convertissez en lignes (et si vous avez vraiment 1000, vous devriez vraiment revoir le modèle de données). Les deux decode les instructions utilisent ce nombre généré pour faire correspondre un nom de colonne et une valeur - exécutez la sélection interne seule pour voir à quoi cela ressemble.

Sans recourir au SQL dynamique, vous ne pouvez pas éviter d'avoir à lister les colonnes - une seule fois avec le vrai unpivot , mais deux fois avec la fausse version 10g, et vous devez vous assurer qu'ils correspondent correctement et que le générateur de numéros de lignes produit suffisamment de valeurs. (Trop et vous pourriez obtenir des résultats étranges, mais comme toutes les valeurs supplémentaires seront nulles ici et que vous utilisez avg , cela n'a pas trop d'importance dans ce cas; tout comme un contrôle de santé mentale, vous devriez probablement le faire correspondre exactement de toute façon).

Ou une autre version, basée sur le fait que vous voulez toujours toutes les colonnes sauf name , ce qui signifie que vous n'avez besoin de lister les colonnes que vous voulez qu'une seule fois et qu'il est plus facile de les faire correspondre visuellement - continuez simplement à ajouter when clauses ; et vous n'avez pas besoin du nombre de lignes :

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