为何仅聚合一个SELECT表达式时,需对所有SELECT项分组/聚合?
核心逻辑:SQL的聚合规则要求明确关联关系
当你在SELECT语句中同时使用非聚合列(比如station_id)和聚合函数(比如AVG())时,数据库必须明确知道这两类数据的对应逻辑,否则就会抛出语法错误。
1. 为什么单独用AVG()不会报错?
当SELECT里只有聚合函数AVG(num_bikes_available)时,这是全局聚合:数据库会计算整个表的num_bikes_available平均值,最终返回1行结果,逻辑完全明确,所以可以正常运行。
示例代码:
SELECT AVG(num_bikes_available) FROM `bigquery-public-data.new_york_citibike.citibike_stations`
查询结果:
| f0_ |
|---|
| 13.249537892791142 |
2. 为什么加station_id不加GROUP BY会报错?
station_id是表中的非聚合列,原表有多少行,就会有多少个station_id(可能重复);而AVG()默认是全局聚合,只返回1行结果。
数据库无法判断你的需求:
- 是要按每个
station_id分组,计算每个站点自己的单车数量平均值? - 还是要给每一个
station_id都配上整个表的全局平均值?
SQL语法规则要求必须通过GROUP BY或聚合函数来明确这个逻辑,所以会报错:
SELECT list expression references column station_id which is neither grouped nor aggregated at [2:3]
3. 为什么GROUP BY station_id能解决报错?
GROUP BY station_id告诉数据库:把表中的数据按station_id分组,每个组内单独计算AVG(num_bikes_available)。这样每个station_id对应自己组的平均值,结果行数和不同的station_id数量一致,逻辑清晰,符合SQL语法要求。
示例代码:
SELECT station_id, AVG(num_bikes_available) FROM `bigquery-public-data.new_york_citibike.citibike_stations` GROUP BY station_id
不过这个查询得到的是每个站点自身的单车数量平均值,和你想要的全局平均值结果不同。
4. 为什么子查询能得到你想要的结果?
你使用的子查询是标量子查询:它会先独立计算出整个表的全局平均值(返回一个单一值),然后数据库会自动把这个值和原表的每一行station_id做关联——相当于给每一行的station_id都“复制”同一个全局平均值,此时SELECT中的station_id是原表的每行数据,子查询结果是固定值,两者的行数匹配(原表有N行,子查询的单一值会重复N次),完全符合SQL的语法规则,所以可以正常运行并得到你想要的结果。
示例代码:
SELECT station_id, (SELECT AVG(num_bikes_available) FROM `bigquery-public-data.new_york_citibike.citibike_stations`) FROM `bigquery-public-data.new_york_citibike.citibike_stations`
查询结果(示例):
| station_id | f0_ |
|---|---|
| 1bb1af93-b433-4da7-8054-009c85f7755a | 13.249537892791142 |
| c638ec67-9ac0-416f-944f-619926144931 | 13.249537892791142 |
| 66de0cab-0aca-11e7-82f6-3863bb44ef7c | 13.249537892791142 |
内容的提问来源于stack exchange,提问作者KingFate

