English 中文(简体)
MySQL:总GROUP BY WITH ROLLUP好奇心
原标题:
  • 时间:2009-03-18 19:50:57
  •  标签:

我有两个查询。其中一个对我有意义,另一个没有。第一个:

SELECT gender AS  Gender , count(*) AS  # 
    FROM registrations 
    GROUP BY gender WITH ROLLUP

那给我的是这个:

Gender       #
Female      20
Male        19
NULL        39

所以,我得到了计数和总计数。这是我预期的。接下来的一个:

SELECT c.printable_name AS  Country , count(*) AS  #  
    FROM registrations r 
    INNER JOIN country c ON r.country = c.country_id 
    GROUP BY country WITH ROLLUP

Country         #
Denmark         9
Norway         10
Sweden         18
United States   1
Uzbekistan      1
Uzbekistan     39

相同的结果。但为什么我得到了乌兹别克斯坦的总分??

最佳回答

但为什么我的总数会是乌兹别克斯坦?

因为你没有选择你按照分组的项目。如果你说:

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中选择列,而不允许具有函数依赖关系的列。因此,它也会使有效的查询失败,使其通常无用。

问题回答
SELECT ifnull(c.printable_name, "Total Registration = ") AS  Country , count(*) AS  #  
FROM registrations r 
INNER JOIN country c ON r.country = c.country_id 
GROUP BY country WITH ROLLUP;

这将打印“总注册数=39”,并将是最后一行/记录。

因为当使用JOIN方法时,数组的下一个NULL元素将具有前一个非NULL元素的值。但是我不确定。这是我在使用PHP时的经验。

hm... there is another problem... Country canot be because it is name of table. So change for something else. Then last result will display NULL. Here is my proposal:

$result = mysql_query("SELECT c.printable_name AS  countryp , count(*) AS  # 
FROM registrations r, country c WHERE r.country = c.country_id
GROUP BY countryp WITH ROLLUP");

while($row = @mysql_fetch_array($result)) {
  $r1 = $row["countryp"];
  $r2 = $row["#"];
  if ($r1 == NULL) $r1 =  Total ;
  echo "$r1 $r2<br />";
}




相关问题
热门标签