类别:

查询语法

GROUP BY

使用相同的逐项分组表达式对行进行分组,并计算结果组的聚合函数。GROUP BY 表达式可以是:

  • 列名称。

  • 引用 SELECT 列表中位置的数字。

  • 通用表达式。

GROUP BY 扩展

GROUP BY 支持以下可提供强大聚合功能的扩展:

  • GROUP BY GROUPING SETS:选择使用 时默认使用的角色和仓库。在单个语句中计算多个 GROUP BY 子句

  • GROUP BY ROLLUP:选择使用 时默认使用的角色和仓库。为分层数据生成小计行

  • GROUP BY CUBE:为所有维度组合生成小计行

您可以将这些扩展与常规 GROUP BY 列结合使用。例如:

  • GROUP BY x, GROUPING SETS(y, z)

  • GROUP BY x, ROLLUP(y, z)

  • GROUP BY x, CUBE(y, z)

有关解读扩展结果中的 NULL 值的更多信息,请参阅 GROUPING 效用函数。

语法

SELECT ...
  FROM ...
  [ ... ]
  GROUP BY groupItem [ , groupItem [ , ... ] ]
  [ ... ]
SELECT ...
  FROM ...
  [ ... ]
  GROUP BY ALL
  [ ... ]

其中:

groupItem ::= { <column_alias> | <position> | <expr> }

参数

column_alias

出现在查询块的 SELECT 列表中的列别名。

position

表达式在 SELECT 列表中的位置。

expr

当前作用域中表的任意表达式。

GROUP BY ALL

指定 SELECT 列表中不使用聚合函数的所有项都应用于分组。

有关示例,请参阅 按所有列分组

使用说明

  • GROUP BY 子句可以按名称或按位置引用投影子句中的表达式。如果 GROUP BY 子句按名称引用,则每个引用的解析方式如下:

    • 如果查询包含具有匹配列名的数据库对象(例如,表或视图),则引用将解析为列名。

    • 否则,如果 SELECT 的投影子句包含具有匹配名称的表达式别名,则引用将解析为该别名。

    有关示例,请参阅 当列名与别名冲突时的优先级

  • 如果所有 SELECT 项都使用聚合函数,则指定 GROUP BY ALL 等同于指定不带 GROUP BY 子句的语句。

    例如,以下语句仅包含使用聚合函数的 SELECT 项:

    SELECT SUM(amount)
      FROM mytable
      GROUP BY ALL;
    

    上面的语句等同于不指定 GROUP by 子句:

    SELECT SUM(amount)
      FROM mytable;
    

示例

以下各节提供了使用 GROUP BY 子句的示例:

请注意,各节中的示例使用您在“为示例设置数据”中设置的数据。

为示例设置数据

本节中的示例使用一个名为 sales 的表和一个名为 product 的表。要创建这些表并插入示例所需的数据,请运行以下命令:

CREATE TABLE sales (
  product_ID INTEGER,
  retail_price REAL,
  quantity INTEGER,
  city VARCHAR,
  state VARCHAR);

INSERT INTO sales (product_id, retail_price, quantity, city, state) VALUES
  (1, 2.00,  1, 'SF', 'CA'),
  (1, 2.00,  2, 'SJ', 'CA'),
  (2, 5.00,  4, 'SF', 'CA'),
  (2, 5.00,  8, 'SJ', 'CA'),
  (2, 5.00, 16, 'Miami', 'FL'),
  (2, 5.00, 32, 'Orlando', 'FL'),
  (2, 5.00, 64, 'SJ', 'PR');

CREATE TABLE products (
  product_ID INTEGER,
  wholesale_price REAL);
INSERT INTO products (product_ID, wholesale_price) VALUES (1, 1.00);
INSERT INTO products (product_ID, wholesale_price) VALUES (2, 2.00);

按一列分组

此示例显示每个产品的总收入,按 product_id 分组(即每个产品收到的总金额):

SELECT product_ID, SUM(retail_price * quantity) AS gross_revenue
  FROM sales
  GROUP BY product_ID;
+------------+---------------+
| PRODUCT_ID | GROSS_REVENUE |
+------------+---------------+
|          1 |          6    |
|          2 |        620    |
+------------+---------------+

以下示例基于上一个示例,显示每个产品的净利润,按 product_id 分组:

SELECT p.product_ID, SUM((s.retail_price - p.wholesale_price) * s.quantity) AS profit
  FROM products AS p, sales AS s
  WHERE s.product_ID = p.product_ID
  GROUP BY p.product_ID;
+------------+--------+
| PRODUCT_ID | PROFIT |
+------------+--------+
|          1 |      3 |
|          2 |    372 |
+------------+--------+

按多列分组

下面的示例演示了如何按多个列进行分组:

SELECT state, city, SUM(retail_price * quantity) AS gross_revenue
  FROM sales
  GROUP BY state, city;
+-------+---------+---------------+
| STATE |   CITY  | GROSS REVENUE |
+-------+---------+---------------+
|   CA  | SF      |            22 |
|   CA  | SJ      |            44 |
|   FL  | Miami   |            80 |
|   FL  | Orlando |           160 |
|   PR  | SJ      |           320 |
+-------+---------+---------------+

按所有列分组

以下示例等同于 按多列分组 中使用的示例。

SELECT state, city, SUM(retail_price * quantity) AS gross_revenue
  FROM sales
  GROUP BY ALL;
+-------+---------+---------------+
| STATE |   CITY  | GROSS REVENUE |
+-------+---------+---------------+
|   CA  | SF      |            22 |
|   CA  | SJ      |            44 |
|   FL  | Miami   |            80 |
|   FL  | Orlando |           160 |
|   PR  | SJ      |           320 |
+-------+---------+---------------+

当列名与别名冲突时的优先级

您可以创建包含与列名相同的别名的查询(但通常不建议这样做):

SELECT x, some_expression AS x
  FROM ...

如果子句中包含的名称同时匹配列名和别名,则该子句将使用列名。以下示例通过 GROUP BY 子句演示了此行为:

创建表并插入行:

CREATE TABLE employees (salary FLOAT, state VARCHAR, employment_state VARCHAR);
INSERT INTO employees (salary, state, employment_state) VALUES
  (60000, 'California', 'Active'),
  (70000, 'California', 'On leave'),
  (80000, 'Oregon', 'Active');

以下查询返回在职员工的薪资总和以及休假员工的薪资总和:

SELECT SUM(salary), ANY_VALUE(employment_state)
  FROM employees
  GROUP BY employment_state;
+-------------+-----------------------------+
| SUM(SALARY) | ANY_VALUE(EMPLOYMENT_STATE) |
|-------------+-----------------------------|
|      140000 | Active                      |
|       70000 | On leave                    |
+-------------+-----------------------------+

接下来的查询使用了别名 state,该别名与查询表中的某一列名相同。在 GROUP BY 子句中使用 state 时,Snowflake 会将其解释为对列名的引用,而非别名。因此,此查询返回的是加利福尼亚州和俄勒冈州员工的薪资总和,但显示的却是 employment_state 信息(例如 Active),而不是具体的州或省份名称:

SELECT SUM(salary), ANY_VALUE(employment_state) AS state
  FROM employees
  GROUP BY state;
+-------------+--------+
| SUM(SALARY) | STATE  |
|-------------+--------|
|      130000 | Active |
|       80000 | Active |
+-------------+--------+