2

在写了几年 SQL 之后,我发现必须将我感兴趣的列SELECT然后在GROUP BY. 我不禁想,我们为什么要这样做?

用户必须具体说明要分组的列的原因是什么?我们不能让 SQL 引擎假设是否存在聚合函数SELECT,按其余非聚合列分组吗?

当您有大量CASE WHENSELECT.

4

3 回答 3

8

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

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

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 子句中使用别名。

于 2017-09-19T18:12:25.580 回答
2

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

如果我不得不猜测,SQL 的作者并不想在聚合函数中注入如此多的力量。您的建议意味着 中的函数select正在确定结果集中行的定义。通常,select只确定列。也就是说,查询在语法上失败是一回事,因为包含的聚合没有group by. select中的函数更改正在输出的行是另一回事。

您可以将窗口函数与select distinct. 虽然我不推荐语法,但你可以这样做:

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

好吧,这消除了group by,但您仍然必须在每个窗口函数中重复分组标准。

于 2017-09-19T18:18:35.437 回答
1

你必须想象你在这里使用了两个版本的表格。例如:

SELECT …
FROM table
GROUP BY …;

首先,请记住,在anbd子句之后SELECT进行评估。这意味着您可以选择的内容受到这些子句结果的限制。FROMGROUP BY

事情是想象GROUP BY生成一个新的虚拟表。这个虚拟表只有以下内容:

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

每个不同的组将有一行摘要。

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

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

请注意,GROUP BY摘要中的行数受您分组的列数的影响。通常,行数类似于 (DISTINCT Group1)*(DISTINCT GROUP2) 等。这意味着您当然不想分组超过您真正需要的数量。

例外

假设你有这样的声明:

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

这当然会失败。name选择一个状态有多个值的地方有什么意义?

然而,在传统模式下,MySQL 将允许您这样做:它会选择一个名称来配合状态。但是,不能保证是哪一个,所以它的价值值得怀疑。

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

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

这只不过是一种解决方法。它利用了每个月份名称恰好有一个月份编号这一事实,因此没有真正的进一步分组。GROUP BY它只是为了在虚拟表中获取两个值。

于 2021-10-24T02:28:42.673 回答