📜 ⬆️ ⬇️

PostgreSQL 9.5: what's new? Part 3. GROUPING SETS, CUBE, ROLLUP

We continue to get acquainted with new features in PostgreSQL 9.5.
Part 1. INSERT ... ON CONFLICT DO NOTHING / UPDATE and ROW LEVEL SECURITY
Part 2. TABLESAMPLE
Today we consider multiple groups in one query. This feature was described in the SQL-99 standard. It is convenient to use it if you need to make several queries to the same table, differing only in the GROUP BY clause . For this, GROUPING SETS, ROLLUP, CUBE modifiers are specified as a grouping element after the GROUP BY keyword.
Let's take a closer look at how this works.

Suppose we have a scheme in which there is data on payments, each payment has a type, a city in which this payment was made and the amount of the payment. The city necessarily has a country and, optionally, a region. Below are the requests to create such a scheme and fill it with data.
Creating a schema
DROP TABLE IF EXISTS payment; DROP TABLE IF EXISTS payment_type; DROP TABLE IF EXISTS city; DROP TABLE IF EXISTS state; DROP TABLE IF EXISTS country; CREATE TABLE country ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL ); CREATE TABLE state ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL, country_id INT REFERENCES country (id) ); CREATE TABLE city ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL, state_id INT NULL REFERENCES state (id), country_id INT NOT NULL REFERENCES country (id), population BIGINT NOT NULL ); CREATE TABLE payment_type ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL ); CREATE TABLE payment ( id BIGSERIAL PRIMARY KEY, payment_type_id INT NOT NULL REFERENCES payment_type (id), city_id INT NOT NULL REFERENCES city (id), amount NUMERIC(10, 2) NOT NULL ); INSERT INTO country (name) VALUES ('Russia'), ('Ukraine'); INSERT INTO state (name, country_id) VALUES ('Moscow region', 1), ('Samara region', 1), ('Kursk region', 1), ('Tatarstan', 1), ('Kiev region', 2), ('Lugansk region', 2), ('Lvov region', 2), ('Odessa region', 2); –-          ,      INSERT INTO city (name, state_id, country_id, population) VALUES ('Moscow', NULL, 1, 12197596), ('Dubna', 1, 1, 75176), ('Samara', 2, 1, 1171820), ('Tolyatti', 2, 1, 719646), ('Syzran', 2, 1, 175222), ('Novokuybyshevsk', 2, 1, 105007), ('Kursk', 3, 1, 435117), ('Kazan', 4, 1, 1205651), ('Kiev', NULL, 2, 2888470), ('Irpen', 5, 2, 39972), ('Borispol', 5, 2, 60102), ('Belaya Tserkov', 5, 2, 211205), ('Lugansk', 6, 2, 417990), ('Lisichansk', 6, 2, 103459), ('Severodonetsk', 6, 2, 108899), ('Popasnaya', 6, 2, 21765), ('Lvov', 7, 2, 729038), ('Drogobych', 7, 2, 76866), ('Odessa', 8, 2, 1017022), ('Izmail', 8, 2, 72501); INSERT INTO payment_type (name) VALUES ('Online'), ('Box office'), ('Terminal'); INSERT INTO payment (payment_type_id, city_id, amount) SELECT ceil(random() * 3), ceil(random() * 20), trunc(cast(random() * 10000 AS NUMERIC), 2) FROM generate_series(1, 10000); 


Suppose we want to get statistics on the amount of payments in each city and in each country. Previously, it was necessary to write a query of the form:
 (SELECT sum(amount), c.country_id, NULL as city_id FROM payment AS p INNER JOIN city AS c ON p.city_id=c.id GROUP BY c.country_id ORDER BY c.country_id) UNION ALL (SELECT sum(amount), NULL, p.city_id FROM payment AS p GROUP BY p.city_id ORDER BY p.city_id) 

Query result
sumcountry_idcity_id
19794121.93oneNull
30138426.572Null
2420939.72Nullone
2611787.51Null2
2357570.54Null3
2796471.48Nullfour
2327588.11Nullfive
2563701.69Null6
2442654.38Null7
2273408.5Nulleight
2509228.24Null9
2716771.77Nullten
2745394.99Nulleleven
2554721.34Null12
2526112.36Null13
2818708.34Null14
2437768.84Null15
2246483.68Nullsixteen
2384795.14Null17
2437849.05Null18
2470876.07Nullnineteen
2289716.75Null20


From version 9.5 it is easier to write a similar request like this:
 SELECT sum(amount), c.country_id, p.city_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(c.country_id, p.city_id); 

Query result
sumcountry_idcity_id
19794121.93oneNull
30138426.572Null
2420939.72Nullone
2611787.51Null2
2357570.54Null3
2796471.48Nullfour
2327588.11Nullfive
2563701.69Null6
2442654.38Null7
2273408.5Nulleight
2509228.24Null9
2716771.77Nullten
2745394.99Nulleleven
2554721.34Null12
2526112.36Null13
2818708.34Null14
2437768.84Null15
2246483.68Nullsixteen
2384795.14Null17
2437849.05Null18
2470876.07Nullnineteen
2289716.75Null20


As you can see, the GROUPING SETS as a result of the query returns data as follows: in each row of one of the columns listed in brackets corresponds to the value, while the remaining columns (from the list in brackets) are filled with NULL. Columns not listed in GROUPING SETS are calculated as usual.

To get the full amount (without grouping), you can use the empty grouping - () . With empty grouping, all fields participating in GROUPING SETS are NULL:
 SELECT sum(amount), p.city_id, c.country_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, C.country_id, ()); 

Query result
sumcountry_idcity_id
19794121.93oneNull
30138426.572Null
49932548.5NullNull
2420939.72Nullone
2611787.51Null2
2357570.54Null3
2796471.48Nullfour
2327588.11Nullfive
2563701.69Null6
2442654.38Null7
2273408.5Nulleight
2509228.24Null9
2716771.77Nullten
2745394.99Nulleleven
2554721.34Null12
2526112.36Null13
2818708.34Null14
2437768.84Null15
2246483.68Nullsixteen
2384795.14Null17
2437849.05Null18
2470876.07Nullnineteen
2289716.75Null20


Now let's try to get the amount of payments in the context of cities, regions and countries:
 SELECT sum(amount), p.city_id, c.state_id, c.country_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id); 

Query result
sumcity_idstate_idcountry_id
2420939.72oneNullNull
2611787.512NullNull
2357570.543NullNull
2796471.48fourNullNull
2327588.11fiveNullNull
2563701.696NullNull
2442654.387NullNull
2273408.5eightNullNull
2509228.249NullNull
2716771.77tenNullNull
2745394.99elevenNullNull
2554721.3412NullNull
2526112.3613NullNull
2818708.3414NullNull
2437768.8415NullNull
2246483.68sixteenNullNull
2384795.1417NullNull
2437849.0518NullNull
2470876.07nineteenNullNull
2289716.7520NullNull
19794121.93NullNullone
30138426.57NullNull2
2611787.51NulloneNull
10045331.82Null2Null
2442654.38Null3Null
2273408.5NullfourNull
8016888.1NullfiveNull
10029073.22Null6Null
4822644.19Null7Null
4760592.82NulleightNull
4930167.96NullNullNull


Strange, we did not make an empty grouping, but received a string in which all fields are NULL. In fact, this happened because the state_id field was not filled in in Moscow and Kiev, therefore GROUPING SETS rightly did the grouping by state_id = NULL . This is easily verified by running the following query:
 SELECT sum(amount) FROM payment WHERE city_id IN (1, 9); 

Query result
sum
4930167.96


Yes, our assumption turned out to be true and the amounts coincided.

Well, where did this strange line come from, we figured it out, but how to distinguish in the next query, which of the lines contains the full amount, and which group is state_id = NULL ?
 SELECT sum(amount), p.city_id, c.state_id, c.country_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id, ()); 

Query result
sumcity_idstate_idcountry_id
2420939.72oneNullNull
2611787.512NullNull
2357570.543NullNull
2796471.48fourNullNull
2327588.11fiveNullNull
2563701.696NullNull
2442654.387NullNull
2273408.5eightNullNull
2509228.249NullNull
2716771.77tenNullNull
2745394.99elevenNullNull
2554721.3412NullNull
2526112.3613NullNull
2818708.3414NullNull
2437768.8415NullNull
2246483.68sixteenNullNull
2384795.1417NullNull
2437849.0518NullNull
2470876.07nineteenNullNull
2289716.7520NullNull
49932548.5NullNullNull
19794121.93NullNullone
30138426.57NullNull2
2611787.51NulloneNull
10045331.82Null2Null
2442654.38Null3Null
2273408.5NullfourNull
8016888.1NullfiveNull
10029073.22Null6Null
4822644.19Null7Null
4760592.82NulleightNull
4930167.96NullNullNull


So in fact, the total value will be greater, you say, and you will be right. Of course, in this query, you can understand that the line with the larger amount is the full amount. However, if the table had not only positive values, but also negative ones, it would be more difficult to determine the full amount. Well, or if you use another aggregate function:
 SELECT avg(amount), p.city_id, c.state_id, c.country_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id, ()); 

Query result
avgcity_idstate_idcountry_id
4841.87944oneNullNull
5141.3139960629921262NullNull
4850.96818930041152263NullNull
4958.2827659574468085fourNullNull
4849.1418958333333333fiveNullNull
5096.82244532803180916NullNull
5208.21829424307036257NullNull
4985.5449561403508772eightNullNull
5038.61092369477911659NullNull
5135.6744234404536862tenNullNull
5219.3821102661596958elevenNullNull
4903.495854126679462612NullNull
5092.968467741935483913NullNull
5006.586749555950266414NullNull
4964.905987780040733215NullNull
4992.1859555555555556sixteenNullNull
4694.478622047244094517NullNull
5047.306521739130434818NullNull
4883.1542885375494071nineteenNullNull
4945.39254859611231120NullNull
4993.25485NullNullNull
4990.9535879979828543NullNullone
4994.7674129930394432NullNull2
5141.313996062992126NulloneNull
4941.1371470732907034Null2Null
5208.2182942430703625Null3Null
4985.5449561403508772NullfourNull
5086.8579314720812183NullfiveNull
5014.53661Null6Null
4866.4421695257315843Null7Null
4912.8924871001031992NulleightNull
4940.0480561122244489NullNullNull


Which line corresponds to the average amount of payment in the table, and which - the average amount in Kiev and Moscow?
Fortunately, there is a solution: the new grouping () function, with the help of it we can find out whether a particular column is participating in a given row in a grouping. If grouping (column_name) returns 0, then column_name participates in the grouping, if 1 - does not participate:
 SELECT avg(amount), p.city_id, c.state_id, c.country_id, grouping(c.state_id) FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id, ()); 

Query result
avgcity_idstate_idcountry_idgrouping
4841.87944oneNullNullone
5141.3139960629921262NullNullone
4850.96818930041152263NullNullone
4958.2827659574468085fourNullNullone
4849.1418958333333333fiveNullNullone
5096.82244532803180916NullNullone
5208.21829424307036257NullNullone
4985.5449561403508772eightNullNullone
5038.61092369477911659NullNullone
5135.6744234404536862tenNullNullone
5219.3821102661596958elevenNullNullone
4903.495854126679462612NullNullone
5092.968467741935483913NullNullone
5006.586749555950266414NullNullone
4964.905987780040733215NullNullone
4992.1859555555555556sixteenNullNullone
4694.478622047244094517NullNullone
5047.306521739130434818NullNullone
4883.1542885375494071nineteenNullNullone
4945.39254859611231120NullNullone
4993.25485NullNullNullone
4990.9535879979828543NullNulloneone
4994.7674129930394432NullNull2one
5141.313996062992126NulloneNull0
4941.1371470732907034Null2Null0
5208.2182942430703625Null3Null0
4985.5449561403508772NullfourNull0
5086.8579314720812183NullfiveNull0
5014.53661Null6Null0
4866.4421695257315843Null7Null0
4912.8924871001031992NulleightNull0
4940.0480561122244489NullNullNull0


In fact, grouping returns a bitmask for the columns listed in it:
 SELECT avg(amount), p.city_id, c.state_id, c.country_id, grouping(p.city_id, c.state_id, c.country_id) FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id, ()); 

Query result
avgcity_idstate_idcountry_idgrouping
4841.87944oneNullNull3
5141.3139960629921262NullNull3
4850.96818930041152263NullNull3
4958.2827659574468085fourNullNull3
4849.1418958333333333fiveNullNull3
5096.82244532803180916NullNull3
5208.21829424307036257NullNull3
4985.5449561403508772eightNullNull3
5038.61092369477911659NullNull3
5135.6744234404536862tenNullNull3
5219.3821102661596958elevenNullNull3
4903.495854126679462612NullNull3
5092.968467741935483913NullNull3
5006.586749555950266414NullNull3
4964.905987780040733215NullNull3
4992.1859555555555556sixteenNullNull3
4694.478622047244094517NullNull3
5047.306521739130434818NullNull3
4883.1542885375494071nineteenNullNull3
4945.39254859611231120NullNull3
4993.25485NullNullNull7
4990.9535879979828543NullNullone6
4994.7674129930394432NullNull26
5141.313996062992126NulloneNullfive
4941.1371470732907034Null2Nullfive
5208.2182942430703625Null3Nullfive
4985.5449561403508772NullfourNullfive
5086.8579314720812183NullfiveNullfive
5014.53661Null6Nullfive
4866.4421695257315843Null7Nullfive
4912.8924871001031992NulleightNullfive
4940.0480561122244489NullNullNullfive


So it is not very clear, we will bring the result to the bit (3) type :
 SELECT avg(amount), p.city_id, c.state_id, c.country_id, grouping(p.city_id, c.state_id, c.country_id) :: BIT(3) FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS(p.city_id, c.state_id, c.country_id, ()); 

Query result
avgcity_idstate_idcountry_idgrouping
4841.87944oneNullNull011
5141.3139960629921262NullNull011
4850.96818930041152263NullNull011
4958.2827659574468085fourNullNull011
4849.1418958333333333fiveNullNull011
5096.82244532803180916NullNull011
5208.21829424307036257NullNull011
4985.5449561403508772eightNullNull011
5038.61092369477911659NullNull011
5135.6744234404536862tenNullNull011
5219.3821102661596958elevenNullNull011
4903.495854126679462612NullNull011
5092.968467741935483913NullNull011
5006.586749555950266414NullNull011
4964.905987780040733215NullNull011
4992.1859555555555556sixteenNullNull011
4694.478622047244094517NullNull011
5047.306521739130434818NullNull011
4883.1542885375494071nineteenNullNull011
4945.39254859611231120NullNull011
4993.25485NullNullNull111
4990.9535879979828543NullNullone110
4994.7674129930394432NullNull2110
5141.313996062992126NulloneNull101
4941.1371470732907034Null2Null101
5208.2182942430703625Null3Null101
4985.5449561403508772NullfourNull101
5086.8579314720812183NullfiveNull101
5014.53661Null6Null101
4866.4421695257315843Null7Null101
4912.8924871001031992NulleightNull101
4940.0480561122244489NullNullNull101


You can also use common grouping and grouping together in a single query using GROUPING SETS :
 SELECT avg(amount), c.country_id, p.payment_type_id, p.city_id, c.state_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY c.country_id, p.payment_type_id, GROUPING SETS(p.city_id, c.state_id, ()); 

Query result
avgcountry_idpayment_type_idcity_idstate_id
5024.1955882352941176oneoneoneNull
4871.1540119760479042oneone2Null
4891.0804861111111111oneone3Null
5130.3479896907216495oneonefourNull
4739.4527586206896552oneonefiveNull
4803.7104oneone6Null
5028.8194375oneone7Null
4903.6742oneoneeightNull
4931.2117088122605364oneoneNullNull
4407.8555056179775281one2oneNull
5068.5559638554216867one22Null
4812.6204093567251462one23Null
4564.1131034482758621one2fourNull
4963.2932530120481928one2fiveNull
5153.3501219512195122one26Null
5446.8668965517241379one27Null
5057.8818012422360248one2eightNull
4917.934422641509434one2NullNull
5146.2380921052631579one3oneNull
5468.14one32Null
4855.5371929824561404one33Null
5137.8994387755102041one3fourNull
4831.1288757396449704one3fiveNull
5353.0667682926829268one36Null
5172.241280487804878one37Null
4989.92one3eightNull
5121.7272005988023952one3NullNull
5224.12456252one9Null
5137.92071428571428572onetenNull
5173.02096256684491982oneelevenNull
4735.60706521739130432one12Null
5248.01942857142857142one13Null
4929.18579787234042552one14Null
5086.2014 1025641025642one15Null
4716.97012738853503182onesixteenNull
4616.26083832335329342one17Null
4756.91756410256410262one18Null
4698.77872727272727272onenineteenNull
5033.88212765957446812one20Null
4947.5598103792415172oneNullNull
5195.4805945945945946229Null
5213.881861702127659622tenNull
5332.292193548387096822elevenNull
4946.3310303030303032212Null
5020.52888888888888892213Null
5019.81819148936170212214Null
4875.53934523809523812215Null
5169.001655172413793122sixteenNull
4605.46018072289156632217Null
4930.97808383233532932218Null
4985.601744186046511622nineteenNull
5137.49430463576158942220Null
5035.322551173240139822NullNull
4654.930718954248366239Null
5048.504624277456647423tenNull
5171.384673913043478323elevenNull
5042.00593023255813952312Null
4997.42880952380952382313Null
5071.09941176470588242314Null
4941.50185628742514972315Null
5110.906283783783783823sixteenNull
4853.56108571428571432317Null
5451.85356252318Null
4958.899881656804733723nineteenNull
4702.79374269005847952320Null
5001.364400592007893423NullNull
4871.1540119760479042oneoneNullone
4904.9742705167173252oneoneNull2
5028.8194375oneoneNull3
4903.6742oneoneNullfour
5024.1955882352941176oneoneNullNull
5068.5559638554216867one2Nullone
4868.3998074074074074one2Null2
5446.8668965517241379one2Null3
5057.8818012422360248one2Nullfour
4407.8555056179775281one2NullNull
5468.14one3Nullone
5045.2698285714285714one3Null2
5172.241280487804878one3Null3
4989.92one3Nullfour
5146.2380921052631579one3NullNull
5012.75936920222634512oneNullfive
4998.67168639053254442oneNull6
4684.19411764705882352oneNull7
4853.18911764705882352oneNulleight
5224.12456252oneNullNull
5163.109645669291338622Nullfive
5015.997844036697247722Null6
4768.707897897897897922Null7
5056.610340557275541822Nulleight
5195.480594594594594622NullNull
5089.132514177693761823Nullfive
5029.117268656716417923Null6
5139.312716417910447823Null7
4830.093558823529411823Nulleight
4654.93071895424836623NullNull


You can combine the columns inside the GROUPING SETS into groups
 SELECT avg(amount), c.country_id, p.payment_type_id, p.city_id, c.state_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY GROUPING SETS((p.payment_type_id, c.country_id), ( c.state_id, p.city_id)); 

Query result
avgcountry_idpayment_type_idcity_idstate_id
4931.2117088122605364oneoneNullNull
4947.5598103792415172oneNullNull
4917.934422641509434one2NullNull
5035.322551173240139822NullNull
5121.7272005988023952one3NullNull
5001.364400592007893423NullNull
5141.313996062992126NullNull2one
4850.9681893004115226NullNull32
4958.2827659574468085NullNullfour2
4849.1418958333333333NullNullfive2
5096.8224453280318091NullNull62
5208.2182942430703625NullNull73
4985.5449561403508772NullNulleightfour
5135.6744234404536862NullNulltenfive
5219.3821102661596958NullNullelevenfive
4903.4958541266794626NullNull12five
5092.9684677419354839NullNull136
5006.5867495559502664NullNull146
4964.9059877800407332NullNull156
4992.1859555555555556NullNullsixteen6
4694.4786220472440945NullNull177
5047.3065217391304348NullNull187
4883.1542885375494071NullNullnineteeneight
4945.392548596112311NullNull20eight
4841.87944NullNulloneNull
5038.6109236947791165NullNull9Null


We now turn to CUBE . CUBE is something like a multiple GROUPING SETS .
CUBE returns data for all possible combinations of columns listed inside. That is, for the case of CUBE ( c1, c2, c3 ) (where c1, c2, c3 are the column names), the following combinations will be returned:
(c1, null, null)
(null, c2, null)
(null, null, c3)
(c1, c2, null)
(c1, null, c3)
(null, c2, c3)
(c1, c2, c3)
(null, null, null)
Example:
 SELECT sum(amount), p.payment_type_id, c.country_id, p.city_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY CUBE(p.payment_type_id, c.country_id, p.city_id); 

Query result
sumpayment_type_idcountry_idcity_id
854113.25oneoneone
813482.72oneone2
704315.59oneone3
995287.51oneonefour
687220.65oneonefive
840649.32oneone6
804611.11oneone7
735551.13oneoneeight
6435231.28oneoneNull
835859.93one29
863170.68one2ten
967354.92one2eleven
871351.7one212
918403.4one213
926686.93one214
793447.42one215
740564.31one2sixteen
770915.56one217
742079.14one218
775298.49one2nineteen
709777.38one220
9914909.86one2Null
16350141.14oneNullNull
784598.282oneone
841380.292one2
822958.092one3
794155.682onefour
823906.682onefive
845149.422one6
789795.72one7
814318.972oneeight
6516263.112oneNull
961163.91229
980209.7922ten
826505.2922eleven
816144.622212
768140.922213
943725.822214
819090.612215
749505.2422sixteen
764506.392217
823473.342218
857523.522nineteen
775761.642220
10085751.0722Null
16602014.182NullNull
782228.193oneone
956924.53one2
830296.863one3
1007028.293onefour
816460.783onefive
877902.953one6
848247.573one7
723538.43oneeight
6842627.543oneNull
712204.4329
873391.332ten
951534.7832eleven
867225.023212
839568.043213
948295.593214
825230.813215
756414.1332sixteen
849373.193217
872296.573218
838054.0832nineteen
804177.733220
10137765.6432Null
16980393.183NullNull
49932548.5NullNullNull
854113.25oneNullone
784598.282Nullone
782228.193Nullone
2420939.72NullNullone
813482.72oneNull2
841380.292Null2
956924.53Null2
2611787.51NullNull2
704315.59oneNull3
822958.092Null3
830296.863Null3
2357570.54NullNull3
995287.51oneNullfour
794155.682Nullfour
1007028.293Nullfour
2796471.48NullNullfour
687220.65oneNullfive
823906.682Nullfive
816460.783Nullfive
2327588.11NullNullfive
840649.32oneNull6
845149.422Null6
877902.953Null6
2563701.69NullNull6
804611.11oneNull7
789795.72Null7
848247.573Null7
2442654.38NullNull7
735551.13oneNulleight
814318.972Nulleight
723538.43Nulleight
2273408.5NullNulleight
835859.93oneNull9
961163.912Null9
712204.43Null9
2509228.24NullNull9
863170.68oneNullten
980209.792Nullten
873391.33Nullten
2716771.77NullNullten
967354.92oneNulleleven
826505.292Nulleleven
951534.783Nulleleven
2745394.99NullNulleleven
871351.7oneNull12
816144.622Null12
867225.023Null12
2554721.34NullNull12
918403.4oneNull13
768140.922Null13
839568.043Null13
2526112.36NullNull13
926686.93oneNull14
943725.822Null14
948295.593Null14
2818708.34NullNull14
793447.42oneNull15
819090.612Null15
825230.813Null15
2437768.84NullNull15
740564.31oneNullsixteen
749505.242Nullsixteen
756414.133Nullsixteen
2246483.68NullNullsixteen
770915.56oneNull17
764506.392Null17
849373.193Null17
2384795.14NullNull17
742079.14oneNull18
823473.342Null18
872296.573Null18
2437849.05NullNull18
775298.49oneNullnineteen
857523.52Nullnineteen
838054.083Nullnineteen
2470876.07NullNullnineteen
709777.38oneNull20
775761.642Null20
804177.733Null20
2289716.75NullNull20
2420939.72Nulloneone
2611787.51Nullone2
2357570.54Nullone3
2796471.48Nullonefour
2327588.11Nullonefive
2563701.69Nullone6
2442654.38Nullone7
2273408.5Nulloneeight
19794121.93NulloneNull
2509228.24Null29
2716771.77Null2ten
2745394.99Null2eleven
2554721.34Null212
2526112.36Null213
2818708.34Null214
2437768.84Null215
2246483.68Null2sixteen
2384795.14Null217
2437849.05Null218
2470876.07Null2nineteen
2289716.75Null220
30138426.57Null2Null


As in GROUPING SETS, you can do grouping inside:
 SELECT sum(amount), p.payment_type_id, c.country_id, p.city_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY CUBE(p.payment_type_id, (c.country_id, p.city_id)); 

Query result
sumpayment_type_idcountry_idcity_id
854113.25oneoneone
813482.72oneone2
704315.59oneone3
995287.51oneonefour
687220.65oneonefive
840649.32oneone6
804611.11oneone7
735551.13oneoneeight
835859.93one29
863170.68one2ten
967354.92one2eleven
871351.7one212
918403.4one213
926686.93one214
793447.42one215
740564.31one2sixteen
770915.56one217
742079.14one218
775298.49one2nineteen
709777.38one220
16350141.14oneNullNull
784598.282oneone
841380.292one2
822958.092one3
794155.682onefour
823906.682onefive
845149.422one6
789795.72one7
814318.972oneeight
961163.91229
980209.7922ten
826505.2922eleven
816144.622212
768140.922213
943725.822214
819090.612215
749505.2422sixteen
764506.392217
823473.342218
857523.522nineteen
775761.642220
16602014.182NullNull
782228.193oneone
956924.53one2
830296.863one3
1007028.293onefour
816460.783onefive
877902.953one6
848247.573one7
723538.43oneeight
712204.4329
873391.332ten
951534.7832eleven
867225.023212
839568.043213
948295.593214
825230.813215
756414.1332sixteen
849373.193217
872296.573218
838054.0832nineteen
804177.733220
16980393.183NullNull
49932548.5NullNullNull
2420939.72Nulloneone
2611787.51Nullone2
2357570.54Nullone3
2796471.48Nullonefour
2327588.11Nullonefive
2563701.69Nullone6
2442654.38Nullone7
2273408.5Nulloneeight
2509228.24Null29
2716771.77Null2ten
2745394.99Null2eleven
2554721.34Null212
2526112.36Null213
2818708.34Null214
2437768.84Null215
2246483.68Null2sixteen
2384795.14Null217
2437849.05Null218
2470876.07Null2nineteen
2289716.75Null220


ROLLUP is the same as CUBE - something like multiple GROUPING SETS , with the difference that ROLLUP generates combinations, removing columns one by one from the end. Thus, ROLLUP ( c1, c2, c3, c4 ) will return the following combinations:
(c1, c2, c3, c4)
(c1, c2, c3, null)
(c1, c2, null, null)
(c1, null, null, null)
(null, null, null, null)
Example:
 SELECT sum(amount), p.payment_type_id, c.country_id, p.city_id FROM payment AS p INNER JOIN city AS c ON p.city_id = c.id GROUP BY ROLLUP(p.payment_type_id, c.country_id, p.city_id); 

Query result
sumpayment_type_idcountry_idcity_id
854113.25oneoneone
813482.72oneone2
704315.59oneone3
995287.51oneonefour
687220.65oneonefive
840649.32oneone6
804611.11oneone7
735551.13oneoneeight
6435231.28oneoneNull
835859.93one29
863170.68one2ten
967354.92one2eleven
871351.7one212
918403.4one213
926686.93one214
793447.42one215
740564.31one2sixteen
770915.56one217
742079.14one218
775298.49one2nineteen
709777.38one220
9914909.86one2Null
16350141.14oneNullNull
784598.282oneone
841380.292one2
822958.092one3
794155.682onefour
823906.682onefive
845149.422one6
789795.72one7
814318.972oneeight
6516263.112oneNull
961163.91229
980209.7922ten
826505.2922eleven
816144.622212
768140.922213
943725.822214
819090.612215
749505.2422sixteen
764506.392217
823473.342218
857523.522nineteen
775761.642220
10085751.0722Null
16602014.182NullNull
782228.193oneone
956924.53one2
830296.863one3
1007028.293onefour
816460.783onefive
877902.953one6
848247.573one7
723538.43oneeight
6842627.543oneNull
712204.4329
873391.332ten
951534.7832eleven
867225.023212
839568.043213
948295.593214
825230.813215
756414.1332sixteen
849373.193217
872296.573218
838054.0832nineteen
804177.733220
10137765.6432Null
16980393.183NullNull
49932548.5NullNullNull


In conclusion, I want to say that, besides the convenience of writing, these queries are potentially (not yet merit), work faster, since to execute a query you need only one table scan instead of several that are performed in the case of UNION ALL .
')
Thanks for attention!

Source: https://habr.com/ru/post/269849/


All Articles