GROUP BY 句
説明
GROUP BY
句は、指定された一連のグルーピング式に基づいて行をグループ化し、1 つ以上の指定された集計関数に基づいて行のグループに対して集計を計算するために使用されます。 Spark はまた、GROUPING SETS
、CUBE
、ROLLUP
句を介して、同じ入力レコードセットに対して複数の集計を行うための高度な集計もサポートしています。グルーピング式と高度な集計は、GROUP BY
句で混在させ、GROUPING SETS
句でネストさせることができます。「混合/ネストされたグルーピング分析」セクションで詳細をご覧ください。 FILTER 句が集計関数に添付されている場合、一致する行のみがその関数に渡されます。
構文
GROUP BY group_expression [ , group_expression [ , ... ] ] [ WITH { ROLLUP | CUBE } ]
GROUP BY { group_expression | { ROLLUP | CUBE | GROUPING SETS } (grouping_set [ , ...]) } [ , ... ]
集計関数は次のように定義されます
aggregate_name ( [ DISTINCT ] expression [ , ... ] ) [ FILTER ( WHERE boolean_expression ) ]
パラメータ
-
group_expression
行をグループ化する基準を指定します。行のグルーピングは、グルーピング式の結果値に基づいて実行されます。グルーピング式は、
GROUP BY a
のような列名、GROUP BY 0
のような列の位置、またはGROUP BY a + b
のような式です。 -
grouping_set
グルーピングセットは、括弧で囲まれた 0 個以上のカンマ区切り式で指定されます。グルーピングセットに要素が 1 つしかない場合は、括弧を省略できます。たとえば、
GROUPING SETS ((a), (b))
はGROUPING SETS (a, b)
と同じです。構文:
{ ( [ expression [ , ... ] ] ) | expression }
-
GROUPING SETS
GROUPING SETS の後に指定された各グルーピングセットの行をグループ化します。たとえば、
GROUP BY GROUPING SETS ((warehouse), (product))
は、GROUP BY warehouse
とGROUP BY product
の結果の和集合と意味的に同等です。この句は、UNION ALL
演算子の各レッグがGROUPING SETS
句で指定された各グルーピングセットの集計を実行するUNION ALL
の省略形です。同様に、GROUP BY GROUPING SETS ((warehouse, product), (product), ())
は、GROUP BY warehouse, product
、GROUP BY product
、およびグローバル集計の結果の和集合と意味的に同等です。**注:** Hive との互換性のために、Spark は
GROUP BY ... GROUPING SETS (...)
を許可します。 GROUP BY 式は通常無視されますが、GROUPING SETS 式よりも多くの式が含まれている場合、追加の式はグルーピング式に含まれ、値は常に null になります。たとえば、SELECT a, b, c FROM ... GROUP BY a, b, c GROUPING SETS (a, b)
では、列c
の出力は常に null です。 -
ROLLUP
単一のステートメントで複数レベルの集計を指定します。この句は、複数のグルーピングセットに基づいて集計を計算するために使用されます。
ROLLUP
はGROUPING SETS
の省略形です。たとえば、GROUP BY warehouse, product WITH ROLLUP
またはGROUP BY ROLLUP(warehouse, product)
は、GROUP BY GROUPING SETS((warehouse, product), (warehouse), ())
と同等です。GROUP BY ROLLUP(warehouse, product, (warehouse, location))
はGROUP BY GROUPING SETS((warehouse, product, location), (warehouse, product), (warehouse), ())
と同等です。ROLLUP
仕様の N 個の要素は、N+1 個のGROUPING SETS
になります。 -
CUBE
CUBE
句は、GROUP BY
句で指定されたグルーピング列の組み合わせに基づいて集計を実行するために使用されます。CUBE
はGROUPING SETS
の省略形です。たとえば、GROUP BY warehouse, product WITH CUBE
またはGROUP BY CUBE(warehouse, product)
はGROUP BY GROUPING SETS((warehouse, product), (warehouse), (product), ())
と同等です。GROUP BY CUBE(warehouse, product, (warehouse, location))
はGROUP BY GROUPING SETS((warehouse, product, location), (warehouse, product), (warehouse, location), (product, warehouse, location), (warehouse), (product), (warehouse, product), ())
と同等です。CUBE
仕様の N 個の要素は、2^N 個のGROUPING SETS
になります。 -
混合/ネストされたグルーピング分析
GROUP BY 句には、複数の
group_expression
と複数のCUBE|ROLLUP|GROUPING SETS
を含めることができます。GROUPING SETS
には、ネストされたCUBE|ROLLUP|GROUPING SETS
句を含めることもできます。たとえば、GROUPING SETS(ROLLUP(warehouse, location), CUBE(warehouse, location))
、GROUPING SETS(warehouse, GROUPING SETS(location, GROUPING SETS(ROLLUP(warehouse, location), CUBE(warehouse, location))))
などです。CUBE|ROLLUP
はGROUPING SETS
の構文糖衣にすぎません。CUBE|ROLLUP
をGROUPING SETS
に変換する方法については、上記のセクションを参照してください。このコンテキストでは、group_expression
は単一グループのGROUPING SETS
として扱うことができます。GROUP BY
句に複数のGROUPING SETS
がある場合、元のGROUPING SETS
のクロス積を実行することにより、単一のGROUPING SETS
を生成します。GROUPING SETS
句にネストされたGROUPING SETS
がある場合は、単にそのグルーピングセットを取得して削除します。たとえば、GROUP BY warehouse, GROUPING SETS((product), ()), GROUPING SETS((location, size), (location), (size), ())
とGROUP BY warehouse, ROLLUP(product), CUBE(location, size)
は、GROUP BY GROUPING SETS( (warehouse, product, location, size), (warehouse, product, location), (warehouse, product, size), (warehouse, product), (warehouse, location, size), (warehouse, location), (warehouse, size), (warehouse))
と同等です。GROUP BY GROUPING SETS(GROUPING SETS(warehouse), GROUPING SETS((warehouse, product)))
は、GROUP BY GROUPING SETS((warehouse), (warehouse, product))
と同等です。 -
aggregate_name
集計関数名 (MIN、MAX、COUNT、SUM、AVG など) を指定します。
-
DISTINCT
集計関数に渡される前に、入力行の重複を削除します。
-
FILTER
WHERE
句のboolean_expression
が true と評価される入力行が集計関数に渡されます。その他の行は破棄されます。
例
CREATE TABLE dealer (id INT, city STRING, car_model STRING, quantity INT);
INSERT INTO dealer VALUES
(100, 'Fremont', 'Honda Civic', 10),
(100, 'Fremont', 'Honda Accord', 15),
(100, 'Fremont', 'Honda CRV', 7),
(200, 'Dublin', 'Honda Civic', 20),
(200, 'Dublin', 'Honda Accord', 10),
(200, 'Dublin', 'Honda CRV', 3),
(300, 'San Jose', 'Honda Civic', 5),
(300, 'San Jose', 'Honda Accord', 8);
-- Sum of quantity per dealership. Group by `id`.
SELECT id, sum(quantity) FROM dealer GROUP BY id ORDER BY id;
+---+-------------+
| id|sum(quantity)|
+---+-------------+
|100| 32|
|200| 33|
|300| 13|
+---+-------------+
-- Use column position in GROUP by clause.
SELECT id, sum(quantity) FROM dealer GROUP BY 1 ORDER BY 1;
+---+-------------+
| id|sum(quantity)|
+---+-------------+
|100| 32|
|200| 33|
|300| 13|
+---+-------------+
-- Multiple aggregations.
-- 1. Sum of quantity per dealership.
-- 2. Max quantity per dealership.
SELECT id, sum(quantity) AS sum, max(quantity) AS max FROM dealer GROUP BY id ORDER BY id;
+---+---+---+
| id|sum|max|
+---+---+---+
|100| 32| 15|
|200| 33| 20|
|300| 13| 8|
+---+---+---+
-- Count the number of distinct dealer cities per car_model.
SELECT car_model, count(DISTINCT city) AS count FROM dealer GROUP BY car_model;
+------------+-----+
| car_model|count|
+------------+-----+
| Honda Civic| 3|
| Honda CRV| 2|
|Honda Accord| 3|
+------------+-----+
-- Sum of only 'Honda Civic' and 'Honda CRV' quantities per dealership.
SELECT id, sum(quantity) FILTER (
WHERE car_model IN ('Honda Civic', 'Honda CRV')
) AS `sum(quantity)` FROM dealer
GROUP BY id ORDER BY id;
+---+-------------+
| id|sum(quantity)|
+---+-------------+
|100| 17|
|200| 23|
|300| 5|
+---+-------------+
-- Aggregations using multiple sets of grouping columns in a single statement.
-- Following performs aggregations based on four sets of grouping columns.
-- 1. city, car_model
-- 2. city
-- 3. car_model
-- 4. Empty grouping set. Returns quantities for all city and car models.
SELECT city, car_model, sum(quantity) AS sum FROM dealer
GROUP BY GROUPING SETS ((city, car_model), (city), (car_model), ())
ORDER BY city;
+---------+------------+---+
| city| car_model|sum|
+---------+------------+---+
| null| null| 78|
| null| HondaAccord| 33|
| null| HondaCRV| 10|
| null| HondaCivic| 35|
| Dublin| null| 33|
| Dublin| HondaAccord| 10|
| Dublin| HondaCRV| 3|
| Dublin| HondaCivic| 20|
| Fremont| null| 32|
| Fremont| HondaAccord| 15|
| Fremont| HondaCRV| 7|
| Fremont| HondaCivic| 10|
| San Jose| null| 13|
| San Jose| HondaAccord| 8|
| San Jose| HondaCivic| 5|
+---------+------------+---+
-- Group by processing with `ROLLUP` clause.
-- Equivalent GROUP BY GROUPING SETS ((city, car_model), (city), ())
SELECT city, car_model, sum(quantity) AS sum FROM dealer
GROUP BY city, car_model WITH ROLLUP
ORDER BY city, car_model;
+---------+------------+---+
| city| car_model|sum|
+---------+------------+---+
| null| null| 78|
| Dublin| null| 33|
| Dublin| HondaAccord| 10|
| Dublin| HondaCRV| 3|
| Dublin| HondaCivic| 20|
| Fremont| null| 32|
| Fremont| HondaAccord| 15|
| Fremont| HondaCRV| 7|
| Fremont| HondaCivic| 10|
| San Jose| null| 13|
| San Jose| HondaAccord| 8|
| San Jose| HondaCivic| 5|
+---------+------------+---+
-- Group by processing with `CUBE` clause.
-- Equivalent GROUP BY GROUPING SETS ((city, car_model), (city), (car_model), ())
SELECT city, car_model, sum(quantity) AS sum FROM dealer
GROUP BY city, car_model WITH CUBE
ORDER BY city, car_model;
+---------+------------+---+
| city| car_model|sum|
+---------+------------+---+
| null| null| 78|
| null| HondaAccord| 33|
| null| HondaCRV| 10|
| null| HondaCivic| 35|
| Dublin| null| 33|
| Dublin| HondaAccord| 10|
| Dublin| HondaCRV| 3|
| Dublin| HondaCivic| 20|
| Fremont| null| 32|
| Fremont| HondaAccord| 15|
| Fremont| HondaCRV| 7|
| Fremont| HondaCivic| 10|
| San Jose| null| 13|
| San Jose| HondaAccord| 8|
| San Jose| HondaCivic| 5|
+---------+------------+---+
--Prepare data for ignore nulls example
CREATE TABLE person (id INT, name STRING, age INT);
INSERT INTO person VALUES
(100, 'Mary', NULL),
(200, 'John', 30),
(300, 'Mike', 80),
(400, 'Dan', 50);
--Select the first row in column age
SELECT FIRST(age) FROM person;
+--------------------+
| first(age, false) |
+--------------------+
| NULL |
+--------------------+
--Get the first row in column `age` ignore nulls,last row in column `id` and sum of column `id`.
SELECT FIRST(age IGNORE NULLS), LAST(id), SUM(id) FROM person;
+-------------------+------------------+----------+
| first(age, true) | last(id, false) | sum(id) |
+-------------------+------------------+----------+
| 30 | 400 | 1000 |
+-------------------+------------------+----------+