tutoriales.com

SQL PIVOT y UNPIVOT: Transforma tus Datos Tabulares como un Experto 🔄

Descubre cómo reestructurar tus conjuntos de datos en bases de datos relacionales utilizando las operaciones PIVOT y UNPIVOT. Domina el arte de crear reportes dinámicos y facilita el análisis de información empresarial.

Intermedio7 min de lectura5 views
Reportar error

¡Bienvenido a esta guía definitiva sobre la transformación de datos tabulares en SQL! Cuando trabajamos con bases de datos relacionales, a menudo nos enfrentamos al desafío de presentar la información de maneras que las consultas tradicionales (como un simple SELECT con GROUP BY) no pueden resolver de forma limpia. Aquí es donde entran en juego las potentes cláusulas PIVOT y UNPIVOT.

💡 Consejo: Dominar estas herramientas te ahorrará horas de procesamiento posterior en herramientas de BI o código de aplicación.

🎯 ¿Qué son PIVOT y UNPIVOT en SQL?

Imagina que tienes una tabla de ventas donde cada fila representa una transacción individual con el mes y el monto. Para un reporte ejecutivo, tu jefe no quiere una lista vertical interminable, sino una matriz cruzada donde las filas sean los productos y las columnas sean los meses del año. Esta transformación mágica de filas a columnas se llama PIVOT.

Por el contrario, ¿qué pasa si recibes un archivo de Excel o una tabla ancha con múltiples columnas de años y necesitas normalizarla para insertarla en una base de datos relacional transaccional? Ahí es donde utilizas UNPIVOT, que convierte las columnas de un conjunto de datos en filas.


🛠️ Preparando el Entorno y los Datos de Prueba

Para entender a fondo cómo funcionan estas operaciones, vamos a crear una tabla de ejemplo llamada VentasTrimestrales. Esta tabla almacenará las ventas de diferentes productos a lo largo de varios trimestres del año.

CREATE TABLE VentasTrimestrales (
    Producto VARCHAR(50),
    Trimestre VARCHAR(10),
    Monto DECIMAL(10, 2)
);

INSERT INTO VentasTrimestrales (Producto, Trimestre, Monto)
VALUES 
('Laptop', 'Q1', 12000.00),
('Laptop', 'Q2', 15000.00),
('Laptop', 'Q3', 18000.00),
('Laptop', 'Q4', 22000.00),
('Smartphone', 'Q1', 8000.00),
('Smartphone', 'Q2', 9500.00),
('Smartphone', 'Q3', 11000.00),
('Smartphone', 'Q4', 14000.00),
('Tablet', 'Q1', 5000.00),
('Tablet', 'Q2', 4800.00),
('Tablet', 'Q3', 6000.00),
('Tablet', 'Q4', 7500.00);

Si ejecutamos un SELECT * FROM VentasTrimestrales, obtendremos una estructura estrictamente vertical (basada en filas).

Tabla Original (Vertical) Tabla Pivotada (Matricial) Producto Trimestre Monto Laptop Q1 $1000 Laptop Q2 $1200 Mouse Q1 $50 Mouse Q2 $60 Teclado Q1 $80 Teclado Q2 $85 PIVOT Producto Q1 Q2 Q3 Q4 Laptop $1000 $1200 - - Mouse $50 $60 - - Teclado $80 $85 - -

📊 Transformando Filas en Columnas con la Operación PIVOT

La sintaxis de PIVOT puede parecer un poco intimidante al principio porque requiere una consulta derivada o una tabla de expresión común (CTE) para aislar los datos que deseas transformar.

Sintaxis General de PIVOT

En la mayoría de los motores de bases de datos que soportan esta sintaxis nativa (como SQL Server y Oracle), la estructura general es la siguiente:

SELECT <columna_no_pivotada>, [columna_1], [columna_2], ...
FROM (
    SELECT <columna_no_pivotada>, <columna_pivotada>, <columna_agregacion>
    FROM <tabla>
) AS SourceTable
PIVOT (
    SUM(<columna_agregacion>)
    FOR <columna_pivotada> IN ([columna_1], [columna_2], ...)
) AS PivotTable;

Ejemplo Práctico de PIVOT

Vamos a aplicar esta estructura a nuestros datos de ventas para mostrar los trimestres como columnas.

SELECT Producto, [Q1], [Q2], [Q3], [Q4]
FROM (
    SELECT Producto, Trimestre, Monto
    FROM VentasTrimestrales
) AS DatosOrigen
PIVOT (
    SUM(Monto)
    FOR Trimestre IN ([Q1], [Q2], [Q3], [Q4])
) AS TablaPivoteada;

Al ejecutar esta consulta, el resultado se verá como una matriz limpia y fácil de leer para cualquier reporte ejecutivo:

ProductoQ1Q2Q3Q4
Laptop12000.0015000.0018000.0022000.00
Smartphone8000.009500.0011000.0014000.00
Tablet5000.004800.006000.007500.00
⚠️ Advertencia: Debes listar explícitamente los valores que se convertirán en columnas dentro de la cláusula IN (...). PIVOT no es dinámico por defecto; si en el futuro agregas 'Q5', tendrás que actualizar la consulta manualmente (a menos que uses SQL dinámico con sp_executesql).

🔄 Transformando Columnas en Filas con UNPIVOT

Ahora hagamos el camino inverso. Supongamos que tenemos una tabla con la estructura horizontal que acabamos de generar, y necesitamos normalizarla nuevamente en un formato vertical para cumplir con las normas de diseño relacional.

Preparando la Tabla Horizontal

Creemos una tabla temporal o permanente con datos ya pivoteados:

CREATE TABLE VentasAnualesHorizontal (
    Producto VARCHAR(50),
    Q1 DECIMAL(10, 2),
    Q2 DECIMAL(10, 2),
    Q3 DECIMAL(10, 2),
    Q4 DECIMAL(10, 2)
);

INSERT INTO VentasAnualesHorizontal (Producto, Q1, Q2, Q3, Q4)
VALUES ('Laptop', 12000.00, 15000.00, 18000.00, 22000.00);

Sintaxis General de UNPIVOT

La operación inversa toma múltiples columnas y las colapsa en pares de atributos y valores:

SELECT <columna_mantener>, <nueva_columna_categoria>, <nueva_columna_valor>
FROM <tabla>
UNPIVOT (
    <nueva_columna_valor> 
    FOR <nueva_columna_categoria> IN ([columna_1], [columna_2], [columna_3], [columna_4])
) AS UnpivotTable;

Ejemplo Práctico de UNPIVOT

Implementemos esto con nuestra tabla horizontal:

SELECT Producto, Trimestre, Monto
FROM VentasAnualesHorizontal
UNPIVOT (
    Monto 
    FOR Trimestre IN (Q1, Q2, Q3, Q4)
) AS TablaDespivoteada;

El resultado devolverá nuevamente los datos en un formato estrictamente vertical:

ProductoTrimestreMonto
LaptopQ112000.00
LaptopQ215000.00
LaptopQ318000.00
LaptopQ422000.00
📌 Nota: Una regla importante de UNPIVOT es que ignora automáticamente las filas donde el valor de la columna evaluada sea NULL, lo cual es excelente para limpiar datos dispersos.

💡 Alternativa con CASE WHEN (Compatible con todos los motores)

Aunque PIVOT y UNPIVOT son nativos en bases de datos como SQL Server y Oracle, motores como MySQL o PostgreSQL no tienen una cláusula PIVOT nativa. Sin embargo, puedes lograr exactamente el mismo resultado utilizando la expresión condicional CASE WHEN junto con funciones de agregación.

Ejemplo de PIVOT usando CASE WHEN en MySQL / PostgreSQL

SELECT 
    Producto,
    SUM(CASE WHEN Trimestre = 'Q1' THEN Monto ELSE 0 END) AS Q1,
    SUM(CASE WHEN Trimestre = 'Q2' THEN Monto ELSE 0 END) AS Q2,
    SUM(CASE WHEN Trimestre = 'Q3' THEN Monto ELSE 0 END) AS Q3,
    SUM(CASE WHEN Trimestre = 'Q4' THEN Monto ELSE 0 END) AS Q4
FROM VentasTrimestrales
GROUP BY Producto;

Esta técnica es altamente recomendada porque es un estándar ANSI SQL, lo que significa que funcionará prácticamente en cualquier sistema de gestión de bases de datos relacionales del mercado.


📋 Resumen de Diferencias Clave

Para consolidar tu aprendizaje, revisa la siguiente tabla comparativa entre ambas operaciones:

CaracterísticaPIVOTUNPIVOT
Propósito principalConvierte filas en columnasConvierte columnas en filas
Función de agregaciónRequerida (SUM, AVG, COUNT, etc.)No requerida
Uso comúnReportes cruzados, matrices de datosNormalización de datos anchos
Compatibilidad con NULLsLos incluye o agrupa según la funciónOmite los valores nulos

❓ Preguntas Frecuentes (FAQ)

¿Puedo hacer un PIVOT con más de una columna de agregación? No directamente en una sola instrucción PIVOT nativa. Si necesitas pivotar múltiples columnas (por ejemplo, Monto y Cantidad), tendrás que realizar consultas separadas y unirlas mediante un JOIN, o utilizar la técnica de CASE WHEN.
¿Qué pasa si mis columnas dinámicas cambian constantemente? Si los valores de tus columnas cambian todo el tiempo (por ejemplo, meses que se agregan cada año), la sintaxis estática de PIVOT no funcionará por sí sola. Necesitarás escribir un script de **SQL Dinámico** que construya la consulta concatenando cadenas de texto basadas en una consulta previa sobre los valores actuales de la tabla.
¿PIVOT afecta el rendimiento de la base de datos? Sí, al igual que los operadores de agregación pesados y los cruces complejos, realizar un PIVOT sobre tablas con millones de registros sin índices adecuados puede consumir muchos recursos. Asegúrate de filtrar los datos (usando WHERE) antes de pasarlos al bloque PIVOT.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!