【问题标题】:mysql world database: select country with max populationmysql世界数据库:选择人口最多的国家
【发布时间】:2013-12-02 02:04:04
【问题描述】:

我想选择人口最多的国家。这是我的查询:

SELECT continent, name, population FROM country HAVING population = MAX(population);

它以某种方式返回 0 行。

如果我使用嵌套查询,它可以工作:

SELECT continent, name, population FROM country WHERE population = (SELECT MAX(population) FROM country);

所以我的问题是:第一个查询有什么问题?

PS:你可以在这里下载数据库: http://dev.mysql.com/doc/index-other.html


好吧,我想我终于弄清楚了整个过程。以下是它的工作原理以及替代建议/解决方案不起作用的原因:

(首先,正如“Dan Bracuk”在他的回答中所说,我们必须将 GROUP BY 与 HAVING 结合起来,并在 SELECT 语句的开头添加聚合函数)

让我们一步一步来试试这个:

SELECT continent, name, population, MAX(population) FROM country;

这为我们生成了在末尾附加 MAX(pop) 的第一行:
“North America”、“Aruba”、“103000”、“1277558000”

所以 MAX(population) 只是一个条目,因此它将行号限制为 1,并且因为我添加了大陆、名称、人口列,mysql 只从表中选择第一行。

所以如果我现在写下来:

SELECT continent, name, population, MAX(population) FROM country HAVING population = MAX(population);

我得到 0 行,因为 103000 不等于 1277558000。

如果我使用:

SELECT continent, name, population, MAX(population) FROM country GROUP BY name;

例如,我得到了所有国家的列表,其中每行 MAX(population) = population。

所以另外添加“HAVING population = MAX(population)”没有任何效果,因为它已经是真的了。

我希望我理解正确,并且可以澄清其他想知道为什么其他解决方案不起作用的人。

【问题讨论】:

  • 这不是HAVING without GROUP BY问题的例子吗?如果是这样,那么这是一个评估问题。
  • 嗯,我认为你是对的。但是,评估问题是什么意思?
  • 我对您的查询失败的原因的解释可能是错误的,但我可以对“没有GROUP BY”问题有所了解。 HAVINGSELECT 之前和GROUP BY 之后进行评估。想象一下你的结果被慢慢过滤了。 FROM 先行动,必要时加入表格。接下来,WHERE 过滤表中的结果。这是对您很重要的部分:GROUP BY 会将这些行分组,然后HAVING 将根据您的条件删除所有不合格的组。 SELECT 现在将进入并处理剩余的列表。这意味着 HAVING 无法在您的 SELECT 上工作。
  • 上述情况很重要,因为您正在做两件事:您在 population 上的引用,但它还不能被引用。此外,您没有GROUP BY 可以“强制”population 出现。我不是 SQL 专家,因此您的查询问题可能不正确。然而,评估的逻辑似乎支持这一点。
  • @moller1111 我已经编辑了我的答案,并认为它完全回答了你的问题。

标签: mysql sql


【解决方案1】:

选择人口,国家 来自世界 其中人口=(从世界中选择最大(人口))

【讨论】:

    【解决方案2】:

    WHERE 子句应用于源表时,HAVING 子句作为返回结果之前的最后一步应用于聚合数据。

    对于 MySQL,这就是您的查询发生的情况:

    • 由于您使用的是聚合函数MAX,MySQL 得出的结论是查询应该是一个聚合
    • 由于没有GROUP BY 子句,因此聚合在返回单行的完整表上
    • 您使用的字段continentnamepopulation在没有聚合函数的情况下不在GROUP BY中,而其他SQL数据库会抛出错误,MySQL实际上只是返回一个不定行
    • HAVING 子句检查返回的行是否具有最大人口数

    通常这应该返回 0 行,但是根据实际表的设置,您实际上可能会得到一个正确的答案,正如您在这个 sql fiddle 中看到的那样:http://sqlfiddle.com/#!2/79835/7,但这具有误导性,并且至少会崩溃.

    如果您使用GROUP BY 子句或MAXCOUNTSUM 等聚合函数,则您的查询是聚合。在这种情况下,您使用的任何字段通常应该包含在 GROUP BY 中或包含在聚合函数中。不这样做可能会导致难以追踪的细微错误。

    另见:GROUP BY behavior when no aggregate functions are present in the SELECT clause

    【讨论】:

      【解决方案3】:
      Select continent, name, sum(population) As sumPop
      From country
      Group By continent
      Order By sumPop Desc
      Limit 1;
      

      哇,经过大量的反复试验,我明白了现在的问题所在。首先,您的初始查询似乎是错误的。使用您正在使用的数据库表,您可以在大陆内拥有多个区域。因此,您的查询将仅返回(如果工作正常)具有单个最大区域的大陆,而不是所有区域的总和。其次,您绝对可以在having 子句中使用max 函数,例如在此示例中:

      Select continent, name, max(population) As sumPop
      From country
      Group By continent
      Having sumPop = max(population)
      

      (如果不按大洲分组,则只能返回一排。)

      但是,这对您来说真的没有用,因为此时,最大人口数就是该行的人口数。不是每一行。这是因为having 子句仅查看该行的值(无论您拥有多少行)。无论如何,如果您想在您的案例中使用having 子句(或者您可以使用我的初始查询),您将需要一个子查询,如下所示。

      Select continent, name, sum(population) As sumPop, maxPop
      From country
      Left Join (Select sum(population) As maxPop
                From country
                Group By continent
                Order By maxPop Desc Limit 1) as TmpTable On (maxPop > 0)
      Group By continent
      Having sumPop = maxPop
      

      http://sqlfiddle.com/#!2/3ab95/26(这个sqlfiddle不包含所有的表行,所以结果可能和你自己的不一样。)

      【讨论】:

      • 他已经写了一个查询来获取人口最多的国家。他在问为什么他的第一个查询没有这样做。
      • 好的,我只是为了测试目的而尝试了这个:“从国家/地区选择大陆,名称,人口 HAVING MAX(人口)> 1;”它只返回一行(第一行),尽管它应该返回几乎所有行。为什么?
      • 使用 HAVING,它返回 0 行。出现 WHERE 语法错误。所以它不起作用。但我也想知道为什么你的建议不起作用。
      • 顺便可以在这里下载数据库:dev.mysql.com/doc/index-other.html
      • 您建议的第一个查询是获得实际答案的好查询。
      【解决方案4】:

      如果您想从表格中给出的城市数中找到具有最大和计数城市的城市名称,那么您可以通过下面给出的查询找到它。

      select max(city),
             max(count(city))
      from emp
      group by city
      having city=max(city);
      
      MAX(city)      |   MAX(COUNT(city))
      -------------------- -------------------
      udhna          |           4
      

      【讨论】:

        【解决方案5】:

        它有几个问题。事实上,在某些数据库引擎中它会抛出错误。

        首先,having 关键字用于聚合结果,而不是字段。这是一个例子。

        select field1, count(*) records
        from sometable
        group by field1
        having records > 10
        

        请注意,某些数据库不允许您在 having 子句中使用别名。

        接下来,你这样说:

        having population = max(population)
        

        max(population) 尚未真正定义。您不是从任何地方选择它。

        【讨论】:

        • 嗯,他们在这里使用它,就像我的例子一样。那是假的吗? w3schools.com/sql/sql_having.asp
        • @moller1111 在链接中的示例中,aggregate_function(column_name)select 子句中定义。这就是他们可以在having 子句中使用它的原因。
        • 那么为什么这不起作用呢? "SELECT 大陆, 名称, 人口, MAX(population) FROM country HAVING population = MAX(population);"
        • @moller1111 我不确定。这就是我自己想知道的。 :/ 这是我明天上班时会检查的东西。哈哈~
        【解决方案6】:

        即使我已经在 cmets 区域发布了我的答案,我还是觉得有义务指出这一点。请注意,这甚至可能不正确,但出于问答目的,我至少必须尝试指出第一个查询有什么问题。

        第一点:这不是完全错的。它恰好是“不合规矩的”。在某些情况下,人们强制执行类似的查询,但这几乎总是需要长时间解释的操作。可以说,“无黑客攻击”,HAVING(几乎)仅适用于 GROUP BY

        其次是SQL的评估流程。我在这里也可能不合时宜,因为我已经有一段时间没有任何 SQL 经验了,但我认为顺序应该保持不变。 FROM-WHERE-GROUP BY-HAVING-SELECT-ORDER BY 是我了解到的第一件事,它就像一个过滤器。当它还没有拉出人口时去寻找HAVING MAX(population) 执行起来有点痛苦。这部分是存在子查询的地方:因此您可以确定一个可以在SELECT 出现之前引用的“目标”值。

        让我们逐步介绍您的第二行,即带有子查询的那一行:FROM country 获取所有国家/地区。然后你在WHERE 部分对 SQL 说,“嘿,让我们设置一个过滤器。但是过滤器需要另一个查询。所以让我们这样做。”它返回一个值,即表的MAX(population。现在,他将该值返回给WHERE,因此WHERE 过滤掉所有人口不等于条件的行。然后它返回该国的大陆、名称和人口。很简单。

        现在,第二个:再次,FROM country 获取所有国家/地区。您没有WHERE,因此您正在使用基表。您也没有输入GROUP BY,没有发生分组。但是随后您输入了 HAVING,因此 SQL 停下来并询问:“我应该丢弃的合格组在哪里?但即使没有组并且有可能这个查询稍微有效,我的 条件在哪里?”所以你提供了一个条件,但这个条件取决于一个简单的事实:MAX(population) 指的?无论如何,您还没有从列表中选择它,因为SELECT 仍然必须发生。

        从本质上讲,这就是你不能做SELECT name FROM country WHERE population = MAX(population) 的部分原因。就流程而言,它不知道最大人口,因为它仍然需要评估。这就像让苹果采摘者从果园里挑选最好的苹果,而他还没有看到所有的苹果。

        【讨论】:

        • 是的,将 MAX(any_col) 添加到 SELECT 部分是正确的。顺便说一句,我终于弄清楚了整个过程并通过在最后附加答案来编辑我的问题。请看。
        【解决方案7】:

        HAVING 子句用于过滤数据同时聚合,如果表已经包含了每个大陆及其总人口,那么你不需要在主查询中使用 max 函数因为会有无需汇总数据。因此,WHERE 在这种情况下就足够了

        此外,您拥有Having population = Max(population) 的位置不会返回任何内容,因为您没有指定max(population) 将从哪个表中获取数据。

        或者,在sqlserver中可以使用子句 Where >= ALL拉取整个表中人口最多的大陆

        select  continent, name
        from country
        where population >= all ( select population
                                    from country
                                   )
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-13
          • 1970-01-01
          • 1970-01-01
          • 2019-04-22
          • 1970-01-01
          相关资源
          最近更新 更多