为什么SQL强迫我在GROUP BY子句中重复SELECT子句中的所有非聚合字段? [关闭]

StackOverflow https://stackoverflow.com/questions/416625

  •  03-07-2019
  •  | 
  •  

这已经困扰了我很长一段时间。

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

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

修改

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

感谢。

有帮助吗?

解决方案

我倾向于同意你的看法 - 这是SQL应该有一些更智能的默认设置来保存我们所有打字的情况之一。例如,想象一下这是否合法:

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

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

当然,“*”这意味着与SELECT子句不同的东西,所以也许一个不同的角色可以更好地工作:

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

还有一些其他领域,其中SQL并不像它那样雄辩。但在这一点上,可能已经根深蒂固地做出了许多重大改变。

其他提示

因为它们是两个不同的东西,你可以按照不在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

我希望/希望我们能尽快看到更全面的内容;关于该主题的SQL历史课将是有用的和信息丰富的。任何人?任何人? Bueller?

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

SQL早于DRY原则,至少就其在实用程序员

并非所有数据库都需要完整列表:例如,Sybase将很乐意执行像

这样的查询
SELECT a, b, COUNT(*)
FROM some_table
GROUP BY a

...(至少每次我不小心碰到这样的怪物)经常导致如此巨大的无意记录集,恐慌请求迅速发生,请求DBA反弹服务器。结果是一种部分笛卡尔积,但我认为在Sybase的部分实际上可能无法正确实现SQL标准。

也许我们需要一个简写形式 - 称之为GroupSelect

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

这样,如果省略聚合函数,解析器只需抛出一个错误。

它的充分理由是,如果未指定所有列,则会经常得到不正确的结果。假设您有三列, col1 col2 col3

假设您的数据如下所示:

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

通过col1,col2 从mytable group中选择col1,col2,sum(col3)
会给出以下结果:

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

它如何解释
通过col1从mytable group中选择col1,col2,sum(col3)

我的猜测是

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

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

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

我同意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>

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

对SQL标准的改进提出建议会很好。我只是不知道它是如何运作的。

实际上,这不是100%的时间吗?是否存在选择中不在GROUP BY中的(非聚合)列的情况?

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

我分享了op的观点,即重复有点烦人,特别是如果非聚合字段包含精细的语句,如ifs和函数以及许多其他东西。如果group by子句中有一些简写,那将是很好的 - 至少是一个列别名。按编号引用列可能是另一种选择,尽管可能有自己的问题。

例如,可能存在这样一种情况:您需要提取所有分组行的ID,以及它们的数量之和。在这种情况下,您可以按名称对它们进行分组,并保留未分组的ID。 SQLite似乎以这种方式工作。

由于group by by结果为一组元组的单个元组,因此其他非group by属性必须仅用于聚合函数。如果你在select中添加非group by属性,则sql cant决定从该组中选择哪个值。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top