GROUP BY句
説明
GROUP BY 句は、指定された1つ以上のグループ化式に基づいて行をグループ化し、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の結果の和集合と意味的に同等です。この句は、GROUPING SETS句で指定された各グループ化セットの集計を実行するUNION ALL演算子の各レッグの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 |
+-------------------+------------------+----------+