Trasponer tabla en Oracle con cláusula PIVOT

La versión 11g de la base de datos Oracle incorpora la cláusula PIVOT que resuelve, en parte, un problema que alguna vez se me presentó y que tuve que resolver con una consulta poco intuitiva y limitada.

Paso a explicar el tema en detalle con el siguiente ejemplo:

Supongamos una tabla donde se guarde el total de las ventas mensuales por distintas compañías:

DROP TABLE test;

CREATE TABLE test (
  company   varchar(12),
  monthy    char(7),
  sales     number
);

INSERT INTO test VALUES ('CMP1','2008-06', 10);
INSERT INTO test VALUES ('CMP1','2008-07', 29);
INSERT INTO test VALUES ('CMP1','2008-08', 39);
INSERT INTO test VALUES ('CMP1','2008-09', 41);
INSERT INTO test VALUES ('CMP1','2008-10', 22);

INSERT INTO test VALUES ('CMP2','2008-06', 13);
INSERT INTO test VALUES ('CMP2','2008-07', 17);
INSERT INTO test VALUES ('CMP2','2008-08', 61);
INSERT INTO test VALUES ('CMP2','2008-09', 55);
INSERT INTO test VALUES ('CMP2','2008-10', 71);

INSERT INTO test VALUES ('CMP3','2008-06', 33);
INSERT INTO test VALUES ('CMP3','2008-07', 18);
INSERT INTO test VALUES ('CMP3','2008-08', 27);
INSERT INTO test VALUES ('CMP3','2008-09'5);
INSERT INTO test VALUES ('CMP3','2008-10', 32);

Para obtener lo totales de ventas por compañía, podemos escribir algo así:

SELECT    company, monthy,SUM(sales)
FROM        test
GROUP BY    company, monthy

Si nuestra intención es disponer estos datos de forma traspuesta, y obtener un listado donde:

  • Cada fila represente una compañía
  • Cada columna represente un valor los meses totalizados

podemos escribir algo así:

SELECT      company,jul,ago,sep
FROM       (  SELECT        company,
                            SUM(case when monthy='2003-07' then sales else NULL end) jul,
                            SUM(case when monthy='2003-08' then sales else NULL end) ago,
                            SUM(case when monthy='2003-09' then sales else NULL end) sep
              FROM        test
                GROUP BY    company );

Donde obtendríamos:

company      jul        ago        sep   
-------- ---------- ---------- ----------
CMP1         29         39         41
CMP2         17         61         55   
CMP3         18         27          5

Si bien, la consulta anterior funciona, no es muy intuitiva. Con la cláusula PIVOT podemos escribir la misma consulta de manera más sencilla y entendible:

SELECT   *
FROM       (  SELECT       company, monthy, sales
             FROM           test ) S
            PIVOT (SUM(sales) FOR monthy IN ('ABC123','DEF456','XYZ987'))
ORDER BY    company;

Esto es solo un comienzo, dejo a vuestra imaginación y uso todas las combinaciones posibles que podemos escribir con esta cláusula.

Vía: Programación PL/SQL

4 comentario en este artículoDeje el suyo
  1. Hay un error en el query siguiente, no es 2003, es 2008

    este seria el correcto

    SELECT company,jul,ago,sep
    FROM ( SELECT company,
    SUM(case when monthy=’2008-07′ then sales else NULL end) jul,
    SUM(case when monthy=’2008-08′ then sales else NULL end) ago,
    SUM(case when monthy=’2008-09′ then sales else NULL end) sep
    FROM test
    GROUP BY company );

  2. Fue de mucha utilidad el ejemplo que pusiste. Aun cuando cuento con oracle 10.x y no puedo usar la cláusula Pivot el procedimiento que describes me ayudó para lograr el objetivo.

    Saludos

  3. Muchas gracias por la info.. muy valiosa..!!

  4. Muchas gracias por la publicacion. Me sirvio de mucho baje un procesos de 8 horas a 2 horas.

    Saludos y continua con esta tarea loable.

Deje su comentario

Por favor, ingrese su nombre

Por favor, ingrese un correo-e válido

Por favor, ingrese su mensaje

luauf.com 2012

WordPress