- 类别:
GROUP BY¶
使用相同的逐项分组表达式对行进行分组,并计算结果组的聚合函数。GROUP BY 表达式可以是:
列名称。
引用 SELECT 列表中位置的数字。
通用表达式。
语法¶
SELECT ...
FROM ...
[ ... ]
GROUP BY groupItem [ , groupItem [ , ... ] ]
[ ... ]
SELECT ...
FROM ...
[ ... ]
GROUP BY ALL
[ ... ]
其中:
GROUP BY groupItem [ , groupItem [ , ... ] ]
指定用于分组的列别名、位置或表达式。对于每个
groupItem
,使用以下语法:groupItem ::= { <column_alias> | <position> | <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 子句包含与列名和别名均匹配的名称,则 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 | +-------------+--------+