在GROUP BY和COUNT之后加入另一个表

时间:2010-06-20 16:42:16

标签: sql count group-by left-join aggregate-functions

我正在尝试理解使用JOINCOUNT(*)GROUP BY进行非常简单的查询的正确方法。我实际上已经开始工作(见下文),但从我读过的内容来看,我正在使用额外的GROUP BY我不应该这样做。

(注意:下面的问题不是我的实际问题(处理更复杂的表),但我试图提出类似的问题)

我有两张桌子:

Table: Person
-------------
key  name     cityKey
1    Alice    1
2    Bob      2
3    Charles  2
4    David    1

Table: City
-------------
key  name
1    Albany
2    Berkeley
3    Chico

我想对返回的人物(带有一些WHERE子句)进行查询

  • 每个城市的匹配人数
  • 城市的关键
  • 城市名称。

如果我这样做

SELECT COUNT(Person.key) AS count, City.key AS cityKey, City.name AS cityName
FROM Person 
LEFT JOIN City ON Person.cityKey = City.key 
GROUP BY Person.cityKey, City.name

我得到了我想要的结果

count   cityKey   cityName
2       1         Albany
2       2         Berkeley

然而,我read投入GROUP BY子句(City.name)的最后一部分只是为了让它工作是错误的。

那么正确的方法是什么?我一直试图谷歌寻求答案,但我觉得有一些基本的东西,我只是没有得到。

4 个答案:

答案 0 :(得分:3)

在这种情况下,我不认为这是“错误的”,因为你在城市名和城市钥匙之间有一对一的关系。您可以重写它,以便您加入子选择以按键获取人数到城市,再次到城市表中获取名称,但有争议的是,这会更好。我猜这是风格和观点的问题。

select PC.ct, City.key, City.name
  from City
  join (select count(Person.key) ct, cityKey key from Person group by cityKey) PC
    on City.key = PC.key

如果我的SQL不太生锈: - )

答案 1 :(得分:3)

  

...我已经读过,抛出GROUP BY子句(City.name)的最后一部分只是为了让它工作是错误的。

你误解了,你倒退了。
标准SQL 要求 您在GROUP BY中指定SELECT中提到的所有未包含在聚合函数中的列。如果您不想要GROUP BY中的某些列,请将它们包装在聚合函数中。根据数据库的不同,您可以使用分析/窗口函数OVER ...

然而,MySQL和SQLite提供了“功能”,您可以在其中省略这些列中的列 - 这导致“为什么这个端口不能从MySQL填充到fill_in_the_blank数据库?!” Stackoverflow和许多其他网站&论坛。

答案 2 :(得分:1)

您的查询仅适用于MySQL,因为您在Person.cityKey上进行分组,但选择city.key。所有其他数据库都要求您使用min(city.key)之类的聚合,或者将City.key添加到group by子句。

由于城市名称和城市密钥的组合是唯一的,因此以下内容是等效的:

select    count(person.key), min(city.key), min(city.name)
...
group by  person.citykey

或者:

select    count(person.key), city.key, city.name
...
group by  person.citykey, city.key, city.name

或者:

select    count(person.key), city.key, max(city.name)
...
group by  city.key

组中的所有行都具有相同的城市名称和密钥,因此如果您使用maxmin汇总无关紧要。

P.S。如果您只想计算不同的人,即使他们有多行,请尝试:

count(DISTINCT person.key)

而不是

count(person.key)

答案 3 :(得分:1)

  

然而,我已经读到了投掷   GROUP BY子句的最后一部分   (City.name)只是为了让它发挥作用   错。

没错。您必须了解查询优化程序如何查看您的查询。解析它的顺序是要求你“抛弃最后一部分”的原因。优化程序会以类似于此顺序的方式查看您的查询:

  • 所需的表已加入
  • 复合数据集通过WHERE子句
  • 进行过滤
  • 剩余的行由GROUP BY子句切割成组,并聚合
  • 然后通过HAVING子句
  • 再次过滤它们
  • 最终通过SELECT / ORDER BY,UPDATE或DELETE进行操作。

这里的要点是,GROUP BY不必命名SELECT中的所有列,但实际上它是相反的 - SELECT不能包含GROUP BY中尚未包含的任何列。