Summary: in this tutorial, you’ll learn how to use the PostgreSQL GROUPING SETS
to create multiple groupings within the same query.
PostgreSQL GROUPING SETS Overview #
In PostgreSQL, the GROUPING SETS
is an advanced feature of the GROUP BY
clause that allows you to create multiple groupings within the same query.
The GROUP BY
clause allows you to create a single grouping. To create multiple groupings, you can create multiple queries using GROUP BY
clauses.
Alternatively, you combine multiple queries with GROUP BY
clauses using UNION
operators.
The GROUPING SETS
enables multiple groupings within the same query without using multiple queries or the UNION
operator.
Here’s the general syntax of the GROUPING SETS
:
SELECT
column1,
column2,
aggregate_function (column3)
FROM
table_name
GROUP BY
GROUPING SETS (
(column1, column2),
(column1),
(column2),
()
);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
In this syntax:
- First, use the
GROUPING SETS
in theGROUP BY
clause. - Second, specify a list of grouping sets in the
GROUPING SETS
.
The query creates four grouping sets:
- The
(column1, column2)
defines a grouping that groups rows bycolumn1
andcolumn2
. - The
(column1)
defines a grouping that groups rows bycolumn1
. - The
(column2)
defines a grouping that groups rows bycolumn2
. - The
()
defines a grouping that represents the aggregation of overall rows.
Note that you can have more or less grouping sets. For example, the following query will return three grouping sets:
SELECT
column1,
column2,
aggregate_function (column3)
FROM
table_name
GROUP BY
GROUPING SETS (
(column1),
(column2),
()
);
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
PostgreSQL GROUPING SETS Example #
We’ll use the following inventory_reports
to illustrate how the GROUPING SETS
works.
Here’s the script for generating inventory_reports table:
CREATE TABLE inventory_reports(
warehouse VARCHAR NOT NULL,
brand VARCHAR NOT NULL,
quantity INT NOT NULL
);
INSERT INTO inventory_reports(warehouse, brand, quantity)
VALUES
('San Jose', 'Apple', 100),
('San Francisco', 'Apple', 200),
('Texas', 'Apple', 300),
('San Jose', 'Samsung', 50),
('San Francisco', 'Samsung', 100),
('Texas', 'Samsung', 150)
RETURNING *;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse | brand | quantity
---------------+---------+----------
San Jose | Apple | 100
San Francisco | Apple | 200
Texas | Apple | 300
San Jose | Samsung | 50
San Francisco | Samsung | 100
Texas | Samsung | 150
Code language: plaintext (plaintext)
The following query uses the GROUPING SETS
to return multiple groupings:
SELECT
warehouse,
brand,
SUM(quantity) total
FROM
inventory_reports
GROUP BY
GROUPING SETS ((warehouse, brand), (warehouse), (brand), ())
ORDER BY
warehouse NULLS LAST,
brand NULLS LAST;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse | brand | total
---------------+---------+-------
San Francisco | Apple | 200
San Francisco | Samsung | 100
San Francisco | NULL | 300
San Jose | Apple | 100
San Jose | Samsung | 50
San Jose | NULL | 150
Texas | Apple | 300
Texas | Samsung | 150
Texas | NULL | 450
NULL | Apple | 600
NULL | Samsung | 300
NULL | NULL | 900
Code language: plaintext (plaintext)
In this example, the GROUPING SETS
creates four groupings:
The grouping (warehouse, brand)
groups inventory by warehouse and brand:
warehouse | brand | total
---------------+---------+-------
San Francisco | Apple | 200
San Francisco | Samsung | 100
San Jose | Apple | 100
San Jose | Samsung | 50
Texas | Apple | 300
Texas | Samsung | 150
Code language: plaintext (plaintext)
The grouping (warehouse)
groups inventory by warehouse:
warehouse | brand | total
---------------+---------+-------
San Francisco | NULL | 300
San Jose | NULL | 150
Texas | NULL | 450
Code language: plaintext (plaintext)
The grouping (brand)
groups inventory by brand:
warehouse | brand | total
---------------+---------+-------
NULL | Apple | 600
NULL | Samsung | 300
Code language: plaintext (plaintext)
The grouping ()
represents the total inventory of all warehouses and brands:
warehouse | brand | total
---------------+---------+-------
NULL | NULL | 900
Code language: plaintext (plaintext)
Selecting Groupings #
The following example uses the GROUPING SETS
to create two groupings:
SELECT
warehouse,
brand,
SUM(quantity)
FROM
inventory_reports
GROUP BY
GROUPING SETS ((warehouse, brand), ())
ORDER BY
warehouse NULLS LAST,
brand NULLS LAST;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse | brand | sum
---------------+---------+-----
San Francisco | Apple | 200
San Francisco | Samsung | 100
San Jose | Apple | 100
San Jose | Samsung | 50
Texas | Apple | 300
Texas | Samsung | 150
NULL | NULL | 900
Code language: plaintext (plaintext)
In this example, the GROUPING SETS
creates two groupings:
- The grouping
(warehouse, brand)
groups inventory by warehouse and brand. - The grouping
()
represents the total inventory of all warehouses and brands.
PostgreSQL GROUPING Function #
The GROUPING
function takes a column and returns 1 if it is aggregated and 0 otherwise.
GROUPING(column_name)
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
For example:
SELECT
warehouse,
brand,
GROUPING(warehouse) warehouse_grouping,
GROUPING(brand) brand_grouping,
SUM(quantity) total
FROM
inventory_reports
GROUP BY
GROUPING SETS ((warehouse), (brand), ())
ORDER BY
warehouse NULLS LAST,
brand NULLS LAST;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse | brand | warehouse_grouping | brand_grouping | total
---------------+---------+--------------------+----------------+-------
San Francisco | NULL | 0 | 1 | 300
San Jose | NULL | 0 | 1 | 150
Texas | NULL | 0 | 1 | 450
NULL | Apple | 1 | 0 | 600
NULL | Samsung | 1 | 0 | 300
NULL | NULL | 1 | 1 | 900
Code language: plaintext (plaintext)
In the output:
- The rows with
brand_grouping 1
show the total inventory of all brands by warehouses. - The rows with
warehouse_grouping 1
show the total inventory of all warehouses by brands. - The rows with
warehouse_grouping
andbrand_grouping 1
show the total inventory of all brands and warehouses.
You can use the GROUPING
function in the HAVING
clause to select rows aggregated by a column.
For example, the following query uses the GROUPING
function to return the rows aggregated by brands:
SELECT
warehouse,
brand,
GROUPING(warehouse) warehouse_grouping,
GROUPING(brand) brand_grouping,
SUM(quantity) total
FROM
inventory_reports
GROUP BY
GROUPING SETS ((warehouse), (brand), ())
HAVING
GROUPING(brand) = 1
ORDER BY
warehouse NULLS LAST,
brand NULLS LAST;
Code language: PostgreSQL SQL dialect and PL/pgSQL (pgsql)
Output:
warehouse | brand | warehouse_grouping | brand_grouping | total
---------------+-------+--------------------+----------------+-------
San Francisco | NULL | 0 | 1 | 300
San Jose | NULL | 0 | 1 | 150
Texas | NULL | 0 | 1 | 450
NULL | NULL | 1 | 1 | 900
Code language: plaintext (plaintext)
Summary #
- Use the PostgreSQL
GROUPING SETS
to create multiple groupings within the same query. - The
GROUPING
function returns 1 if the column is aggregated or 0 otherwise.