36

这困扰了我很长时间。

99% 的情况下,GROUP BY 子句是 SELECT 子句的精确副本,减去聚合函数(MAX、SUM 等)。
这打破了不要重复自己的原则。

GROUP BY 子句何时不能包含 SELECT 子句减去聚合函数的精确副本?

编辑

我意识到某些实现允许您在 GROUP BY 中拥有与 SELECT 中不同的字段(因此是 99%,而不是 100%),但这肯定是一个非常小的例外吗?
如果您使用不同的字段,有人可以解释应该返回什么吗?

谢谢。

4

10 回答 10

17

我倾向于同意你的观点——这是 SQL 应该具有稍​​微更智能的默认值以节省我们所有输入的许多情况之一。例如,想象一下这是否合法:

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By *

其中“*”表示“所有非聚合字段”。如果每个人都知道它是如何工作的,那么就不会有混乱了。如果你想做一些棘手的事情,你可以加入一个特定的字段列表,但是 splat 的意思是“所有的 'em”(在这种情况下意味着所有可能的)。

当然,“*”在这里的含义与 SELECT 子句中的不同,所以也许不同的字符会更好:

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By !

在其他一些领域,SQL 就没有它可能的那样雄辩。但在这一点上,它可能过于根深蒂固,无法进行如此多的重大改变。

于 2009-01-06T14:38:29.917 回答
7

因为它们是两个不同的东西,您可以按不在 select 子句中的项目分组

编辑:

另外,做出这样的假设是否安全?

我有一条 SQL 语句

Select ClientName, InvAmt, Sum(PayAmt) as PayTot

服务器假设我想按 ClientName 和 InvoiceAmount 分组是否“正确”?我个人更喜欢(并且认为它更安全)拥有此代码

Select ClientName, InvAmt, Sum(PayAmt) as PayTot
Group By ClientName

抛出错误,提示我将代码更改为

Select ClientName, Sum(InvAmt) as InvTot, Sum(PayAmt) as PayTot
Group By ClientName
于 2009-01-06T14:05:47.130 回答
3

我希望/期待我们很快会看到更全面的东西;有关该主题的 SQL 历史课程将很有用且内容丰富。任何人?任何人?布勒?

与此同时,我可以观察到以下情况:

SQL 早于 DRY 原则,至少在The Pragmatic Programmer中有记载。

并非所有数据库都需要完整列表:例如,Sybase 会愉快地执行查询,例如

SELECT a, b, COUNT(*)
FROM some_table
GROUP BY a

... 这(至少每次我不小心运行了这样一个怪物)经常导致如此庞大的无意记录集,以至于恐慌的请求很快接踵而至,请求 DBA 反弹服务器。结果是一种部分笛卡尔积,但我认为这可能主要是 Sybase 未能正确实施 SQL 标准。

于 2009-01-06T14:09:31.957 回答
2

这样做的充分理由是,如果您没有指定所有列,您将经常得到不正确的结果。假设您有三列col1col2col3

假设您的数据如下所示:

Col1  Col2 Col3
a      b    1
a      c    1
b      b    2
a      b    3

select col1, col2, sum(col3) from mytable group by col1, col2
将给出以下结果:

Col1  Col2 Col3
a      b    4
a      c    1
b      b    2

它会如何解释
select col1, col2, sum(col3) from mytable group by col1

我的猜测是

Col1  Col2 Col3
a      b    5
a      c    5
b      b    2

这些显然是不好的结果。当然,查询越复杂,连接越多,查询返回正确结果或程序员甚至知道它们是否不正确的可能性就越小。

我个人很高兴这group by需要这些字段。

于 2009-01-06T19:43:49.927 回答
2

也许我们需要一个速记形式——称之为 GroupSelect

GroupSelect Field1, Field2, sum(Field3) From SomeTable Where (X = "3")

这样,如果您遗漏聚合函数,解析器只需要抛出错误。

于 2009-01-06T20:25:54.320 回答
2

我同意 GROUP BY ALL、GROUP BY * 或类似内容。如原始帖子中所述,在 99%(可能更多)的情况下,您希望按所有非聚合列/表达式进行分组。

但是,出于向后兼容性的原因,这是一个需要 GROUP BY 列的示例。

SELECT 
  MIN(COUNT(*)) min_same_combination_cnt, 
  MAX(COUNT(*)) max_same_comb_cnt, 
  AVG(COUNT(*)) avg_same_comb_cnt, 
  SUM(COUNT(*)) total_records,
  COUNT(COUNT(*)) distinct_combinations_cnt
FROM <some table>
GROUP BY <list of columns>

这适用于甲骨文。我用它来估计列的选择性。group by 应用于内部聚合函数。然后,应用外部聚集体。

如果对 SQL 标准的改进提出建议,那就太好了。我只是不知道这是怎么回事。

于 2012-07-16T18:43:59.687 回答
1

实际上,这不是100%的时间吗?有没有一种情况,您可以在选择中拥有一个不在 GROUP BY 中的(非聚合)列?

虽然我没有答案。对于这门语言来说,这确实是一个尴尬的时刻。

于 2009-01-06T14:03:33.297 回答
1

我同意 op 的观点,即重复有点烦人,特别是如果非聚合字段包含复杂的语句,如 if 和函数以及许多其他内容。如果 group by 子句中可以有一些速记,那就太好了——至少是一个列别名。按编号引用列可能是另一种选择,尽管它可能有自己的问题。

于 2009-01-06T20:18:51.557 回答
0

例如,您可能需要从所有分组的行中提取一个 id,以及它们的数量之和。在这种情况下,您将按名称对它们进行分组,而不将 id 分组。SQLite 似乎以这种方式工作。

于 2012-02-11T15:45:06.113 回答
0

由于 group by 导致整个元组组的单个元组,因此其他非 group by 属性必须仅在聚合函数中使用。如果您在选择中添加非分组属性,则 sql 无法决定从该组中选择哪个值。

于 2013-03-04T20:23:02.327 回答