SQL相关子查询事件序列

SQL相关子查询事件序列,sql,postgresql,greatest-n-per-group,correlated-subquery,Sql,Postgresql,Greatest N Per Group,Correlated Subquery,此查询查找每个大陆上面积最大的国家。它显示了大陆、名称和地区 SELECT c1.continent, c1.name, c1.area FROM countries c1 WHERE c1.area = ( SELECT MAX(c2.area) FROM countries c2 WHERE c1.continent = c2.continent )

此查询查找每个大陆上面积最大的国家。它显示了大陆、名称和地区

SELECT
  c1.continent,
  c1.name,
  c1.area
FROM
  countries c1
WHERE
  c1.area = (
        SELECT
          MAX(c2.area)
        FROM
          countries c2
        WHERE
          c1.continent = c2.continent
        )
如果我理解正确,子查询将把c1中每个条目的大陆与具有相同大陆的所有c2条目进行匹配,并找到最大值。如果是这样,子查询将针对c1中的每个条目运行。这看起来不必要吗


有人能解释一下在这个查询中发生的事件的顺序吗?如果有更好的方法的话。谢谢。

您需要了解SQL查询是非过程性的:它们描述的是结果集,而不是如何创建结果集

如果countriescontinent、area上有一个索引,那么子查询只是在索引中查找,这是一个非常高效的操作

如果索引不可用,那么一些数据库引擎足够聪明,可以将子查询作为一种连接操作来实现——如果数据足够大,通常使用哈希连接


诚然,有些数据库会为外部查询中的每一行运行子查询,本质上是执行嵌套循环联接。但是不要求引擎执行此操作。

您需要了解SQL查询是非过程性的:它们描述结果集,而不是如何创建结果集

如果countriescontinent、area上有一个索引,那么子查询只是在索引中查找,这是一个非常高效的操作

如果索引不可用,那么一些数据库引擎足够聪明,可以将子查询作为一种连接操作来实现——如果数据足够大,通常使用哈希连接


诚然,有些数据库会为外部查询中的每一行运行子查询,本质上是执行嵌套循环联接。但不要求引擎执行此操作。

戈登已经回答了关于如何处理此操作的部分

如果您想知道Postgres是否将相关子查询重新写入联接-请使用explain Analysis…检查执行计划

如果有更好的方法

有。使用标准SQL时,使用窗口函数通常会更快:

select continent, name, area
from (
  select continent, name, area, 
         dense_rank() over (partition by continent order by area desc) as rnk
  from countries
) t
where rnk = 1;
select distinct on (continent) * 
from countries 
order by continent, area desc 
使用distinct on的Postgres通常比使用窗口函数的解决方案更快:

select continent, name, area
from (
  select continent, name, area, 
         dense_rank() over (partition by continent order by area desc) as rnk
  from countries
) t
where rnk = 1;
select distinct on (continent) * 
from countries 
order by continent, area desc 

戈登已经回答了关于如何处理这一问题的部分

如果您想知道Postgres是否将相关子查询重新写入联接-请使用explain Analysis…检查执行计划

如果有更好的方法

有。使用标准SQL时,使用窗口函数通常会更快:

select continent, name, area
from (
  select continent, name, area, 
         dense_rank() over (partition by continent order by area desc) as rnk
  from countries
) t
where rnk = 1;
select distinct on (continent) * 
from countries 
order by continent, area desc 
使用distinct on的Postgres通常比使用窗口函数的解决方案更快:

select continent, name, area
from (
  select continent, name, area, 
         dense_rank() over (partition by continent order by area desc) as rnk
  from countries
) t
where rnk = 1;
select distinct on (continent) * 
from countries 
order by continent, area desc 

您正在使用哪个数据库?我的意思是Oracle、MySQL或SQL Server?@gordon linoff的答案是一个非常好的答案。至于更有效的方法,根据您的RDBMS,我建议使用SELECT I.name子查询,rownum=按i.大陆划分的行数,按i.地区划分的顺序,从国家i开始,加入条件包括rownum=1,这将为您提供每个大陆上最大国家的名称。@Aruna我正在使用Postgres@Forty3是的,我这周刚学了分区,我还在想你在用哪个数据库?我的意思是Oracle、MySQL或SQL Server?@gordon linoff的答案是一个非常好的答案。至于更有效的方法,根据您的RDBMS,我建议使用SELECT I.name子查询,rownum=按i.大陆划分的行数,按i.地区划分的顺序,从国家i开始,加入条件包括rownum=1,这将为您提供每个大陆上最大国家的名称。@Aruna我正在使用Postgres@Forty3是的,这周我刚学会了分区,我仍在努力解决这个问题