Está en la página 1de 11

Inicio Noticias Articulos Cdigo Foros Enlaces Hosting Anuncios

Categoras destacadas

Artculo
Inicio Artculo BBDD

12
votar!

CUBE y ROLLUP del SQL

1 . Introduccin 2 . Primera pregunta: Cuntos transacciones tenemos de entrada y de salida? 3 . Segunda Pregunta: Qu divisa es la ms usada? 4 . Tercera pregunta: Cantidad de cada tipo de transaccin en cada tipo de divisa? 5 . Cuarta pregunta: Y si quiero la informacin agrupada de ms maneras? 6 . Quinta pregunta: cmo sabemos cual de los NULL es un super agregado y cual es un NULL de

verdad?

7 . Sexta pregunta: Podemos mejorar el aspecto del resultado? 8 . Sptima pregunta: Podemos saberlo todo? 9 . Octava pregunta: Y qu pasa con el ROLLUP? 10 . Novena pregunta: Esto se parece al COMPUTE BY verdad? 11 . Dcima pregunta: Muy bonito todo esto, pero si lo hago con un montn de datos en varias tablas,
no ser muy

lento?

12 . ltima pregunta: Es esto todo?

Introduccin
Cuando tenemos que mostrar informacin de nuestra base de datos a los usuarios habitualmente creamos informes con Visual Basic, con Crystal Reports, con los Analysis Services de Microsoft SQL Server 2000 o con lo que queramos. Con estas herramientas podemos realizar cualquier tipo de clculo sobre los datos almacenados, y especialmente calcular sumas, totales, promedios. . . Pero el lenguaje SQL tambin nos proporciona herramientas para hacer la mayor parte del trabajo en el servidor (ahorrndonos posteriores problemas). Como ya conoceris tenemos clusulas como GROUP BY para agrupar, las funciones de agregado para contar, sumar, promediar. y la clusula COMPUTE BY para hacer resmenes. Y si queremos calcular subtotales y totales generales en una misma consulta? Pues tambin existen las clusulas CUBE y ROLLUP que son las que vamos a tratar aqu.

Qu preguntas solucionamos con CUBE y ROLLUP?


Vamos a trabajar con la siguiente tabla por no complicar los ejemplos ni el cdigo SQL. Adems una tabla como esta aunque no sea real sirve perfectamente para mostrar como funciona WITH CUBE.

Id ------------1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

TipoTransaccion -------------------Entrada Entrada Salida Entrada Salida Entrada Entrada Salida Entrada Entrada Entrada Salida Entrada Salida Entrada Entrada Entrada Salida Entrada Salida Entrada Entrada Entrada Entrada

Divisa ---------------Euro Euro Dolar Libra Dolar Euro Dolar Libra Euro Libra Yen Libra Euro Yen Libra Euro Euro Dolar Dolar Libra Euro Libra Yen Libra

Cantidad ----------200 1300 2000 500 1000 300 5000 500 700 400 20000 300 4000 30000 3000 400 900 4000 1200 900 2100 200 25000 400

25 Entrada 26 Entrada (26 filas afectadas)

Euro NULL

700 2000

Es una tabla en la que se guarda informacin sobre transacciones econmicas en las que tenemos tres tipos de datos. Si la transaccin es de entrada o de salida, la moneda en la que se hace y la cantidad. Ahora vamos a empezar a hacer preguntas de tipo OLAP (on-line analytical processing) para analizar los datos que tenemos almacenados.

Primera pregunta: Cuntos tenemos de entrada y de salida?

transacciones

Bueno, para resolver esto podemos escribir una consulta sencilla con un GROUP BY y un COUNT

SELECT TipoTransaccion, COUNT(IdTransaccion) Cantidad FROM Movimientos GROUP BY TipoTransaccion TipoTransaccion Cantidad -------------------------------------- ----------Entrada 18 Salida 7 (2 filas afectadas)

Segunda Pregunta: Qu divisa es la ms usada?


Esta es un poco ms elaborada pero de nuevo nos basta con usar un GROUP BY. Tambin utilizamos TOP 1 para quedarnos slo con el valor ms alto despus de ordenar la suma de manera descendente.

SELECT TOP 1 Divisa, SUM(Cantidad) Suma FROM Movimientos GROUP BY Divisa ORDER BY SUM(Cantidad) DESC Divisa Suma -------------------------------------- ----------Yen 75000 (1 filas afectadas)

Tercera pregunta: Cantidad de cada tipo de transaccin en cada tipo de divisa?


Aqu tenemos que agrupar por TipoTransaccion y Divisa para obtener la suma de las cantidades por esos conceptos. Podemos ver cuantos Euros han salido o cuantos dlares han entrado.

SELECT

TipoTransaccion, Divisa, SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa ORDER BY TipoTransaccion

TipoTransaccion Divisa Cantidad --------------------------- ------------------ ----------Entrada Dolar 6200 Entrada Euro 10600 Entrada Libra 4500 Entrada Yen 45000

Salida Salida Salida (7 filas afectadas)

Dolar Libra Yen

7000 1700 30000

Sin embargo esto no responde a todas las preguntas que podemos hacer.

Cuarta pregunta: Y si quiero la informacin agrupada de ms maneras?


Por ejemplo para saber el total entrante, o el balance de Yenes habr que hacer clculos adicionales o bien con nuevas consultas o bien en nuestra aplicacin cliente. Pero ahora tenemos WITH CUBE que nos permite crear nuevas dimensiones en nuestras consultas. Cuando usamos esta clusula es como si estuvisemos haciendo a la vez todos los GROUP BY posibles y adems mostrndolos en un nico resultset. Aadamos el WITH CUBE a la sentencia anterior

SELECT

TipoTransaccion, Divisa, SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa WITH CUBE TipoTransaccion Divisa Cantidad ------------------------------ ------------------ ----------Entrada Dolar 6200 Entrada Euro 10600 Entrada Libra 4500 Entrada Yen 45000 Entrada NULL 66300 Salida Dolar 7000 Salida Libra 1700 Salida Yen 30000 Salida NULL 38700 NULL NULL 105000 NULL Dolar 13200 NULL Euro 10600 NULL Libra 6200 NULL Yen 75000 (14 filas afectadas)

Aqu hay unos cuantos cambios. Primero vemos que sin necesidad de decirlo los datos se han ordenado por TipoTransaccion y dentro de TipoTransaccion por Divisa. Adems aparecen varios NULL por el medio de la tabla. Pero no os preocupis que todo va bien y vamos a explicar este resultado con calma. Ahora cada fila es una de las posibles combinaciones de TipoTransaccion con Divisa, y las filas que contienen un NULL se tienen que leer pensando que donde est el NULL debera poner "todas". Es decir la fila

NULL

Dolar

13200

Quiere decir que la cantidad total de Dlares tanto en entradas como en salidas (todos los TiposTransaccipn) es 13200 La fila

Entrada

NULL

66300

Quiere decir que hay un valor total de 66300 para todas las entradas (es decir, para todas las divisas) y por ltimo la fila

NULL

NULL

105000

Nos indica que el total de movimientos (todos los TipoTransaccion) de entrada y salida en cualquier divisa (todas las divisas) es de 105000 Como vemos el NULL representa un super agregado en la columna en la que est colocado. Este tipo de NULL no lo debemos confundir con un NULL normal. Ya sabis que un NULL normal indica que desconocemos el valor mientras que este NULL indica una agrupacin. Vamos a insertar una nueva fila en nuestra tabla

INSERT INTO Movimientos (TipoTransaccion, Divisa, Cantidad) VALUES ('Entrada', NULL, 2000)

Qu ocurre ahora si repetimos la consulta?

Quinta pregunta: cmo sabemos cual de los NULL es un super agregado y cual es un NULL de verdad?
Hay una funcin llamada GROUPING que nos dice cuando nuestro NULL es de verdad y cuando no. Esta funcin nos devuelve un 1 si el nombre de la columna pasada como parmetro se usa como resumen y un 0 si no es as. Veamos un ejemplo

SELECT

TipoTransaccion, Divisa, 'Todas las Divisas'=GROUPING(Divisa), SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa WITH CUBE Divisa -------------NULL Dolar Euro Libra Yen NULL Dolar Libra Yen NULL NULL NULL Dolar Euro Libra Yen Todas las Divisas -------------------0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 Cantidad ----------2000 6200 10600 4500 45000 68300 7000 1700 30000 38700 107000 2000 13200 10600 6200 75000

TipoTransaccion ----------------------Entrada Entrada Entrada Entrada Entrada Entrada Salida Salida Salida Salida NULL NULL NULL NULL NULL NULL

(16 filas afectadas)

Como veis hay dos tipos de NULL en la columna de divisas. Las que corresponden al ltimo registro que insertamos que tiene un NULL en divisa, y al que la funcin GROUPING le asocia un 0, y el NULL que podemos traducir por "Todas las divisas" al que la funcin GROUPING le asocia un 1.

Sexta pregunta: Podemos mejorar el aspecto del resultado?


Ahora mezclamos estas funciones nuevas con dos funciones conocidas, CASE e ISNULL para darle un aspecto ms elegante al Resulset obtenido.

SELECT

TipoTransaccion, 'Divisa'= CASE WHEN GROUPING(Divisa)=1 THEN 'Todas' ELSE ISNULL(Divisa, 'N/D') END, SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa WITH CUBE Divisa -------------------N/D Dolar Euro Libra Yen Todas Dolar Libra Yen Todas Todas N/D Dolar Euro Libra Yen Cantidad ----------2000 6200 10600 4500 45000 68300 7000 1700 30000 38700 107000 2000 13200 10600 6200 75000

TipoTransaccion -------------------Entrada Entrada Entrada Entrada Entrada Entrada Salida Salida Salida Salida NULL NULL NULL NULL NULL NULL (16 filas afectadas)

Todo queda ms claro en este resultado. Donde pone "todas" en la columna de divisas quiere decir precisamente eso, y donde pone "N/D" pues quiere decir no disponible.

Sptima pregunta: Podemos saberlo todo?


Pues ahora ya s. Vamos a poner la consulta que nos devuelve toda la informacin que podemos pedir a los datos iniciales.

SELECT 'TipoTransacion'= CASE WHEN GROUPING(TipoTransaccion)=1 THEN 'Todas'

ELSE ISNULL(TipoTransaccion, 'N/D') END, 'Divisa'= CASE WHEN GROUPING(Divisa)=1 THEN 'Todas' ELSE ISNULL(Divisa, 'N/D') END, SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa WITH CUBE TipoTransacion ----------------------Entrada Entrada Entrada Entrada Entrada Entrada Salida Salida Salida Salida Todas Todas Todas Todas Todas Todas (16 filas afectadas) Divisa ---------------N/D Dolar Euro Libra Yen Todas Dolar Libra Yen Todas Todas N/D Dolar Euro Libra Yen Cantidad ----------2000 6200 10600 4500 45000 68300 7000 1700 30000 38700 107000 2000 13200 10600 6200 75000

De esta consulta podemos sacar todas las respuestas a cualquier pregunta que nos hagan sobre los datos iniciales.

Octava pregunta: Y qu pasa con el ROLLUP?


Mientras que WITH CUBE genera un conjunto de resultados que muestra agregados para todas las combinaciones de valores de las columnas seleccionadas, WHIT ROLLUP genera un conjunto de resultados que muestra agregados para una jerarqua de valores de las columnas seleccionadas. Es decir, con CUBE aparecen los resultado totalizados por TipoTransaccion, por Divisa, y por totales absolutos, mientras que con ROLLUP slo apareceran los totales agrupados por lo que nosostros indiquemos. Vemoslo agrupando por TipoTransaccion:

SELECT 'TipoTransacion'= CASE WHEN GROUPING(TipoTransaccion)=1 THEN 'Todas' ELSE ISNULL(TipoTransaccion, 'N/D') END, 'Divisa'= CASE WHEN GROUPING(Divisa)=1 THEN 'Todas' ELSE ISNULL(Divisa, 'N/D') END, SUM(Cantidad) Cantidad FROM Movimientos GROUP BY TipoTransaccion, Divisa

WITH ROLLUP TipoTransacion ------------------------Entrada Entrada Entrada Entrada Entrada Entrada Salida Salida Salida Salida Todas (11 filas afectadas) Divisa -----------------N/D Dolar Euro Libra Yen Todas Dolar Libra Yen Todas Todas Cantidad ----------2000 6200 10600 4500 45000 68300 7000 1700 30000 38700 107000

Obtenemos menos informacin que con WITH CUBE pero de manera ms clara. Adems muchas veces con esto ser suficiente

Novena pregunta: Esto se parece al COMPUTE BY verdad?


MEste tipo de consultas a alguno le traer a la memoria una clusula de SQL Server llamada COMPUTE BY, que hace prcticamente lo mismo pero de diferente manera. Ejecutemos esta consulta

SELECT TipoTransaccion, Divisa, Cantidad FROM Movimientos ORDER BY TipoTransaccion, Divisa COMPUTE SUM(Cantidad) BY TipoTransaccion, Divisa TipoTransaccion Divisa Cantidad ---------------------- ------------------- ----------Entrada NULL 2000 sum =========== 2000 TipoTransaccion ---------------------Entrada Entrada Divisa ------------------Dolar Dolar Cantidad ----------1200 5000 sum =========== 6200 TipoTransaccion ---------------------Entrada Entrada Entrada Entrada Entrada Entrada Entrada Divisa Cantidad ------------------- ----------Euro 4000 Euro 300 Euro 400 Euro 900 Euro 200 Euro 1300 Euro 700

Entrada Entrada

Euro Euro

2100 700 sum =========== 10600

TipoTransaccion ---------------------Entrada Entrada Entrada Entrada Entrada

Divisa ------------------Libra Libra Libra Libra Libra

Cantidad ----------400 200 400 500 3000 sum =========== 4500

TipoTransaccion ---------------------Entrada Entrada

Divisa -------------------Yen Yen

Cantidad ----------20000 25000 sum =========== 45000

TipoTransaccion ---------------------Salida Salida Salida

Divisa -------------------Dolar Dolar Dolar

Cantidad ----------1000 2000 4000 sum =========== 7000

TipoTransaccion ---------------------Salida Salida Salida

Divisa -------------------Libra Libra Libra

Cantidad ----------500 300 900 sum =========== 1700

TipoTransaccion Divisa Cantidad ---------------------- -------------------- ----------Salida Yen 30000 sum =========== 30000 (34 filas afectadas)

Es otra manera de obtener resultados agrupados, pero tiene un par de inconvenientes. El primero y ms importante es que el ROLLUP produce una salida una salida relacional que se pueda almacenar como una vista, utilizar en el FROM de otra consulta o enviar al cliente para ser manejada como un Recordset de Visual Basic. El resultado de un COMPUTE BY tiene una serie de filas adicionales un poco "incmodas" si queremos usar ese resultado para algo ms que mostrarselo al usuario. Y la segunda razn para no usarla es que Microsoft incluye el COMPUTE BY por compatibilidad y no recomienda su uso (en .Net olvidaros de usar COMPUTE BY)

Dcima pregunta: Muy bonito todo esto, pero si lo hago con un montn de datos en varias tablas, no ser muy lento?
S. Si la cantidad de datos a tratar es muy grande este tipo de consultas pueden consumir muchos recursos y tiempo, pero hay muchas soluciones para que esto no sea un problema. Por ejemplo cuando tenemos una consulta que va a resumir una serie de datos y la vamos a necesitar habitualmente podemos convertirla en una vista o guardar el resultado en una tabla, y as podemos recurrir al resultado sin perder tiempo volviendo a ejecutar la sentencia SQL. Siguiendo con nuestro ejemplo podemos almacenar el resultado que obtuvimos con el CUBE en una tabla nueva con SELECT . . . INTO

SELECT 'TipoTransacion'= CASE WHEN GROUPING(TipoTransaccion)=1 THEN 'Todas' ELSE ISNULL(TipoTransaccion, 'N/D') END, 'Divisa'= CASE WHEN GROUPING(Divisa)=1 THEN 'Todas' ELSE ISNULL(Divisa, 'N/D') END, SUM(Cantidad) Cantidad INTO Resumen FROM Movimientos GROUP BY TipoTransaccion, Divisa WITH CUBE select * from resultado

Ahora podemos recurrir a la informacin ya tratada leyendo la tabla Resumen

ltima pregunta: Es esto todo?


No, ni mucho menos. Aqu slo tenemos una muestra de lo que se puede hacer con lenguaje SQL para analizar la informacin que hay en nuestros datos. Y si alguien est interesado en esto del procesado analtico lo visto aqu ni siquiera es la punta del iceberg!! De todos modos es un comienzo

Publicado por: Hiram Cintron Recomendar a un amigo Compartir en redes

Comentarios

Busca

BBDD Entornos de desarrollo Entretenimiento Herramientas Internet Lenguajes de script Lenguajes imperativos Lenguajes orientados a objeto Otros lenguajes Plataformas Teora Varios

ltimas noticias
Novedades que presenta Rails 4 Database Comparer VCL Los lenguajes de programacin ms populares en 2013 Programa tus propias postales navideas
Ver ms

ltimos artculos
Hadoop en Azure I: Qu es Haddop? Conectar con un SQLServer en otro dominio: va cdigo .Net. Impersonacion. BizTalk Server 2010 y EDI para novatos Conectar con un SQLServer en otro dominio
Ver ms

ltimos cdigos
MessageBox sencillo con JQuery UI Mascara para Text (SWT) Convierte cursor de lectura en cursor de escritura Tres en Raya o Juego del Gato
Ver ms

Copyright 1998-2013 Programacin en Castellano. Todos los derechos reservados Datos legales | Politica de privacidad | Contacte con nosotros | Publicidad Diseo web y desarrollo web. Un proyecto de los hermanos Carrero. Red internet: Juegos gratis | cloud hosting Ms internet: Password | Directorio de weblogs | Favicon