Saltar a contenido

Empecemos creando una nueva tabla llamada ventas para la demostración.

DROP TABLE IF EXISTS sales;

CREATE TABLE sales (
    brand VARCHAR NOT NULL,
    segment VARCHAR NOT NULL,
    quantity INT NOT NULL,
    PRIMARY KEY (brand, segment)
);

INSERT INTO sales (brand, segment, quantity)
VALUES
    ('ABC', 'Premium', 100),
    ('ABC', 'Basic', 200),
    ('XYZ', 'Premium', 100),
    ('XYZ', 'Basic', 300);Code language: SQL (Structured Query Language) (sql)

img

La tabla sales almacena el número de productos vendidos por marca y segmento.

Introducción a GROUPING SETS

Un conjunto de agrupación es un conjunto de columnas por las que se agrupa usando la cláusula GROUP BY.

Un conjunto de agrupación es denotado por una lista de columnas separadas por comas colocadas dentro de paréntesis:

(column1, column2, ...)

Por ejemplo, la siguiente consulta utiliza la cláusula GROUP BY para devolver el número de productos vendidos por marca y segmento. En otras palabras, define un conjunto de agrupación de la marca y el segmento que se denota por (brand, segement).

SELECT
    brand,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    brand,
    segment;Code language: SQL (Structured Query Language) (sql)

img

La siguiente consulta busca el número de productos vendidos por una marca. Define un conjunto de agrupación (marca):

SELECT
    brand,
    SUM (quantity)
FROM
    sales
GROUP BY
    brand;Code language: SQL (Structured Query Language) (sql)

img

La siguiente consulta busca el número de productos vendidos por segmento. Define un conjunto de agrupación (segmento):

SELECT
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    segment;
Code language: SQL (Structured Query Language) (sql)

img

La siguiente consulta busca el número de productos vendidos para todas las marcas y segmentos. Define un conjunto de agrupación vacío que se denota por ().

SELECT SUM (quantity) FROM sales;Code language: SQL (Structured Query Language) (sql)

img

Supongamos que desea obtener todos los conjuntos de agrupación utilizando una única consulta. Para conseguirlo, puede utilizar UNION ALL para combinar todas las consultas anteriores.

Dado que UNION ALL requiere que todos los conjuntos de resultados tengan el mismo número de columnas con tipos de datos compatibles, deberá ajustar las consultas añadiendo NULL a la lista de selección de cada una de ellas, como se muestra a continuación:

SELECT
    brand,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    brand,
    segment

UNION ALL

SELECT
    brand,
    NULL,
    SUM (quantity)
FROM
    sales
GROUP BY
    brand

UNION ALL

SELECT
    NULL,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    segment

UNION ALL

SELECT
    NULL,
    NULL,
    SUM (quantity)
FROM
    sales;
Code language: SQL (Structured Query Language) (sql)

img

Esta consulta generó un único conjunto de resultados con los agregados de todos los conjuntos de agrupación.

Aunque la consulta anterior funciona como se esperaba, tiene dos problemas principales.

  • Primero, es bastante larga.
  • Segundo, tiene un problema de rendimiento porque PostgreSQL tiene que escanear la tabla sales por separado para cada consulta.

Para hacerlo más eficiente, PostgreSQL proporciona la cláusula GROUPING SETS que es la subcláusula de la cláusula GROUP BY.

La cláusula GROUPING SETS permite definir múltiples conjuntos de agrupación en la misma consulta.

La sintaxis general de GROUPING SETS es la siguiente:

SELECT
    c1,
    c2,
    aggregate_function(c3)
FROM
    table_name
GROUP BY
    GROUPING SETS (
        (c1, c2),
        (c1),
        (c2),
        ()
);Code language: SQL (Structured Query Language) (sql)

En esta sintaxis, tenemos cuatro conjuntos de agrupación (c1,c2), (c1), (c2) y ().

Para aplicar esta sintaxis al ejemplo anterior, puede utilizar la cláusula GROUPING SETS en lugar de la cláusula UNION ALL de la siguiente manera:

SELECT
    brand,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    GROUPING SETS (
        (brand, segment),
        (brand),
        (segment),
        ()
    );Code language: SQL (Structured Query Language) (sql)

img

Esta consulta es mucho más corta y legible. Además, PostgreSQL optimizará el número de veces que escanea la tabla sales y no la escaneará varias veces.

Función de agrupación

La función GROUPING() acepta un argumento que puede ser un nombre de columna o una expresión:

GROUPING( nombre_columna | expresión)

El nombre_columna o expresión debe coincidir con el especificado en la cláusula GROUP BY.

La función GROUPING() devuelve el bit 0 si el argumento es miembro del conjunto de agrupación actual y 1 en caso contrario.

Véase el siguiente ejemplo:

SELECT
    GROUPING(brand) grouping_brand,
    GROUPING(segment) grouping_segment,
    brand,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    GROUPING SETS (
        (brand),
        (segment),
        ()
    )
ORDER BY
    brand,
    segment;Code language: SQL (Structured Query Language) (sql)

PostgreSQL GROUPING SETS - GROUPING function.

Como se muestra en la captura de pantalla, cuando el valor en el grouping_brand es 0, la columna sum muestra el subtotal de la brand.

Cuando el valor del grouping_segment es cero, la columna suma muestra el subtotal del segment.

Puede utilizar la función GROUPING() en la cláusula HAVING para encontrar el subtotal de cada marca de la siguiente manera:

SELECT
    GROUPING(brand) grouping_brand,
    GROUPING(segment) grouping_segment,
    brand,
    segment,
    SUM (quantity)
FROM
    sales
GROUP BY
    GROUPING SETS (
        (brand),
        (segment),
        ()
    )
HAVING GROUPING(brand) = 0  
ORDER BY
    brand,
    segment;

PostgreSQL GROUPING SETS - GROUPING function in HAVING clause

Resumen

  • Utilice el GROUPING SETS de PostgreSQL para generar múltiples conjuntos de agrupación.