但为什么我的总数会是乌兹别克斯坦?
因为你没有选择你按照分组的项目。如果你说:
GROUP BY c.printable_name
您将获得预期的NULL。但是,由于您正在按不同的列进行分组,因此MySQL不知道printable_name正在参与一个汇总组,并从该列的所有注册的连接中选择任何旧值。 (因此,您可能会看到比乌兹别克斯坦更多的国家。)
这是MySQL存在的一个更广泛问题的一部分,它对于GROUP BY查询中可以SELECT的内容过于宽容。例如,您可以这样说:
SELECT gender FROM registrations GROUP BY country;
MySQL会很高兴地从每个国家的注册中选择一个性别值,即使国家和性别之间没有直接的因果关系(也称为“功能依赖”)。其他数据库管理系统将拒绝上述命令,理由是不能保证每个国家都有一个性别。 (*)
现在,这个:
SELECT c.printable_name AS Country , count(*) AS #
FROM registrations r
INNER JOIN country c ON r.country = c.country_id
GROUP BY country
没问题,因为假设您已将您的country_id正确描述为主键,r.country和c.printable_name之间存在函数依赖关系。
然而,MySQL 的 WITH ROLLUP 扩展是一种有些欺骗性的方式。在最后的 rollup 行阶段,它运行整个预分组结果集以获取其值,然后将 group-by 列设置为 NULL。 它不会将其他具有对该列的函数依赖关系的列也设置为 NULL。 它可能应该这样做,但是 MySQL 目前并不真正理解有关函数依赖关系的整个事情。
如果您选择c.printable_name,它将向您显示它随机选择的任何国家名称值,如果您选择c.country_id,它将向您显示它随机选择的任何国家ID——即使c.country_id是联接条件,因此必须与r.country相同,r.country是NULL!
你可以做的是解决问题的方法是:
- group by printable_name instead; should be OK if printable_names are unique, or
- select “r.country” as well as printable_name, and check that for being NULL, or
- forget WITH ROLLUP and do a separate query for the end sum. This will be a little slower but it will also be ANSI SQL-92 compliant so your app could work on other databases.
MySQL有一个SQL_MODE选项ONLY_FULL_GROUP_BY,旨在解决此问题,但它做得过于严格,只允许您从GROUP BY中选择列,而不允许具有函数依赖关系的列。因此,它也会使有效的查询失败,使其通常无用。