sql >> Base de Datos >  >> RDS >> Oracle

Oracle10G SQL:convertir columnas en filas

Si estuviera en 11G, podría 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

Pero como no lo eres, puedes fingir. Adaptado de este sitio :

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

En ambos casos, el select interno está transformando filas en columnas; en 10g solo tienes que hacerlo tu mismo. El SELECT ... CONNECT BY ... solo genera una lista de valores ficticios, y esto debe tener suficiente para cubrir la cantidad de columnas que está convirtiendo en filas (y si realmente tiene 1000, realmente debería revisar el modelo de datos). Los dos decode Las declaraciones usan ese número generado para hacer coincidir el nombre y el valor de una columna:ejecute la selección interna por sí sola para ver cómo se ve.

Sin recurrir a SQL dinámico, no puede evitar tener que enumerar las columnas, solo una vez con el unpivot real , pero dos veces con la versión falsa de 10 g, y debe asegurarse de que coincidan correctamente y que el generador de números de fila produzca suficientes valores. (Demasiados y es posible que obtenga resultados extraños, pero como cualquier valor adicional será nulo aquí y está usando avg , no importa demasiado en este caso; solo como una verificación de cordura, probablemente debería hacer que coincida exactamente de todos modos).

O otra versión, basada en que siempre quieres todas las columnas excepto name , lo que significa que solo necesita enumerar las columnas que desea una vez y es más fácil hacerlas coincidir visualmente; solo siga agregando when cláusulas; y no necesita el recuento de filas:

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