SQL 标准中是否真的需要 GROUP BY

Is it really necessary to have GROUP BY in the SQL standard

在写了几年SQL之后,我发现不得不把我感兴趣的栏目放在SELECT中,然后在GROUP BY中再次指定它们,这常常很烦人。我不禁想,为什么我们必须这样做?

用户必须具体说明分组依据的列的原因是什么?我们不能让 SQL 引擎假设 如果 SELECT 中有聚合函数,按其余非聚合列分组 ?

当您在 SELECT 中有一个大的 CASE WHEN 时,这将特别有用并且更加简洁。

因为它们可能并不总是完全匹配。

例如,如果我想找出每个类别的最大图书数量,我可以这样做:

select max(cnt)
from (
    select count(*) as cnt
    from books
    group by category
    ) t;

在某些数据库中,例如 Oracle,您甚至可以这样做:

select max(count(*))
from books
group by category;

我真的不需要指定类别列,因为我不需要它。

少数数据库如 Postgres 支持在 group by 子句中使用别名。

我碰巧有点同意你的看法。如果有人想要更深奥的 group by——比如,省略列——那么他们可以使用子查询。

如果非要我猜的话,SQL 的作者不想在聚合函数中赋予如此强大的功能。您的建议意味着 select 中的函数正在确定结果集中行的定义。通常,select 只是确定列。也就是说,查询失败 语法 是一回事,因为包含的聚合没有 group byselect 中的函数更改正在输出的行是另一回事。

您可以将 window 函数与 select distinct 一起使用。虽然我不推荐语法,但你可以这样做:

select distinct x, count(*) over (partition by x)
from t;

好吧,这消除了 group by,但您仍然需要在每个 window 函数中重复分组标准。

您必须想象您正在使用这里的 table 的两个版本。例如:

SELECT …
FROM table
GROUP BY …;

首先,请记住 SELECT FROMGROUP BY 子句之后计算。这意味着您可以 select 受到这些子句结果的限制。

假设 GROUP BY 生成一个新的 virtual table。此虚拟 table 只有以下内容:

  • 分组的列
  • 所有列的摘要(聚合)
  • 没有别的

每个distinct组会有一排摘要。

如果您想要在 SELECT 子句中使用特定的列,它必须是组列或摘要,因为您只能 SELECT 可用的内容。

即使没有 GROUP BY 子句,也有一个隐含的 GROUP BY () 会导致单行摘要。一些 DBMS(不是全部)甚至允许您添加它,尽管它不会改变任何东西。

请注意,GROUP BY 摘要中的行数受您要分组的列数的影响。一般来说,行数将类似于 (DISTINCT Group1)*(DISTINCT GROUP2) 等。这意味着您当然不希望按实际需要的数量进行分组。

异常

假设你有这样的陈述:

SELECT state, name, count(*)
FROM customers
GROUP BY state;

这当然会失败。一个状态有多个值的select和name是什么意思?

但是,在传统模式下,MySQL 会让您做到这一点:它将 select 一个 名称与状态一起使用。但是,无法保证是哪一个,所以它的价值值得怀疑。

假设您要按月分组。您可能希望显示月份名称,但按月份编号排序。在这里,您需要按两者分组。使用伪日期函数:

SELECT monthname, count(*)
FROM data
GROUP BY monthname, monthnumber
ORDER BY monthnumber;

这只不过是一种解决方法。它利用了这样一个事实,即对于每个月份名称,只有一个月份编号,因此没有真正的进一步分组。它只是为了在 GROUP BY 虚拟 table.

中获取两个值