【问题标题】:SQL help with MAX queryMAX 查询的 SQL 帮助
【发布时间】:2011-10-01 23:54:36
【问题描述】:

我有一张名为 bbc(name, region, area, population, gdp) 的国家/地区表

我想要一张表格,其中包含按地区划分的最大(人口最多)国家的地区、名称和人口。到目前为止,我已经尝试过:

SELECT region, name, MAX(population)
FROM bbc
GROUP BY region

它给了我一个错误信息:ORA-00979: Not a GROUP BY Expression

我尝试更改为 GROUP BY 区域、名称,但它没有给我正确的表格

【问题讨论】:

  • 第二个MAX(population) 是怎么回事?你在哪里看到的?
  • 好的,但不要让它再次发生:p

标签: sql oracle aggregate-functions ora-00979


【解决方案1】:

您可以对这样的查询使用分析:

SELECT name, region, population
  FROM (SELECT region, name, population
             , MAX(population) OVER (PARTITION BY region) maxpop
          FROM bbc)
 WHERE population = maxpop;

内联视图为您提供了一个看起来像您的基表的表,以及一个包含该地区最大人口的额外列。您的顶级选择会为您提供每个地区最大国家/地区的国家、地区和人口。

用一个有限的例子来说明:

SELECT * FROM bbc;

REGION          NAME        POPULATION
--------------- -------     ----------
North America   USA         300000000
North America   Canada      100000000
North America   Mexico       50000000
South America   Brazil       50000000
South America   Argentina    40000000
South America   Venezuela    20000000

添加解析函数:

SELECT region, NAME, population
     , MAX(population) OVER (PARTITION BY region) maxpop
  FROM bbc;

REGION          NAME                POPULATION      MAXPOP
--------------- -------             ----------      ----------
North America   USA                 300000000       300000000
North America   Canada              100000000       300000000
North America   Mexico               50000000       300000000
South America   Brazil               50000000        50000000
South America   Argentina            40000000        50000000
South America   Venezuela            20000000        50000000

然后是成品:

NAME    REGION             POPULATION
------- ---------------    -----------
USA     North America       300000000
Brazil  South America        50000000

再修改一次。您可以避免嵌套选择,但不能避免子查询:

SELECT NAME, region, population
  FROM bbc
 WHERE (region, population) IN
       (SELECT region, MAX(population)
          FROM bbc
         group by region);

【讨论】:

  • 对于给定的地区,如果两个国家有相同的人口(我认为这不太可能,但总是值得一问),这个查询将返回两者:这是 tiagovrtr 正在等待的吗?
  • 谁知道?不符合要求!
  • @BrunoGautier 当然可以,但我试图不使用嵌套选择。不可能吗?
  • @OMG,总是有不止一种方法可以做到这一点;-) 我想知道是否存在性能差异......
  • @tiagovtr,不知道为什么要避免嵌套选择,但我的编辑显示了如何使用子查询来做到这一点。
【解决方案2】:

这是最简单最快捷的方法,因为Oracle有元组测试,它可以使代码更短:

首先,获取每个区域的最大人口数:

SELECT region, MAX(population)
FROM bbc
GROUP BY region

然后针对它测试国家/地区:

select region, name, population 
from bbc 
where (region, population) in
      (SELECT region, MAX(population)
       FROM bbc
       GROUP BY region)
order by region

如果您想支持多个 RDBMS,请使用 EXISTS:

select region, name, population 
from bbc o
where exists
      (SELECT null -- neutral. doesn't invoke Cargo Cult Programming ;-)
       FROM bbc
       WHERE region = o.region 
       GROUP BY region
       HAVING o.population = MAX(population) )
order by region

这里测试的查询,都有相似的输出:http://sqlzoo.net/0.htm

http://www.ienablemuch.com/2010/05/why-is-exists-select-1-cargo-cult.html

【讨论】:

  • 这两个查询的成本(解释计划)都比使用分析的查询高。这完全取决于您的目标。
  • 这是明目张胆的断言 ;-) 我们在进行什么预分析?我可以大胆猜测,这种方法所涉及的计算机科学内容比分析还多,这种功能在 CTE/Windowing/Analytics 出现之前很久就存在了。 C/C++ 实现方面,分析内部有许多 ifs,它处理许多功能,所以它会更慢吗?可能是。只是我的2美分。答案是配置文件
  • 远未证明——只是观察优化器认为查询的执行成本。您绝对正确,证明在指标中。
【解决方案3】:

在绝大多数花瓶中,ORA-00979 错误是因为 GROUP BY 子句中未包含非聚合列。在这种情况下,您还需要在 GROUP BY 子句中包含 name。此外,您不应在 FROM 语句中调用 MAX 函数。

SELECT region, name, MAX(population)
FROM bbc
GROUP BY region, name

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 2022-07-04
    • 2016-08-10
    • 1970-01-01
    相关资源
    最近更新 更多