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

Oracle10G SQL:Forvandling af kolonner til rækker

Hvis du var på 11G, kunne du bruge 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

Men da du ikke er det, kan du fake det. Tilpasning fra dette websted :

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

I begge tilfælde er den indre select omdanner rækker til kolonner; i 10g skal du bare gøre det selv. SELECT ... CONNECT BY ... genererer bare en liste over dummy-værdier, og denne skal have nok til at dække antallet af kolonner, du konverterer til rækker (og hvis du virkelig har 1000, bør du virkelig gense datamodellen). De to decode sætninger bruger det genererede tal til at matche et kolonnenavn og en værdi - kør den indre markering alene for at se, hvordan den ser ud.

Uden at ty til dynamisk SQL kan du ikke komme væk fra at skulle liste kolonnerne - kun én gang med den rigtige unpivot , men to gange med den falske 10g-version, og du skal sikre dig, at de matcher korrekt, og at rækkenummergeneratoren producerer nok værdier. (For mange, og du kan få mærkelige resultater, men da alle ekstra værdier vil være nul her, og du bruger avg , det betyder ikke så meget i dette tilfælde; bare som en fornuftskontrol bør du nok få det til at matche nøjagtigt alligevel).

Eller en anden version, baseret på at du altid vil have alle kolonnerne undtagen name , hvilket betyder, at du kun behøver at angive de kolonner, du ønsker én gang, og det er nemmere at matche dem visuelt - bare fortsæt med at tilføje when klausuler; og du behøver ikke rækkeantallet:

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



  1. Mysql slette ældre dubletter

  2. Forberedt erklæring, der ikke lader mig kalde $mysqli->stmt_init()

  3. Hammervægt/befolkningstal i T-SQL

  4. Oracle funktionsbaserede indekser