仅使用JOIN替换相关的子查询?

时间:2013-02-21 17:30:29

标签: sql oracle query-optimization subquery correlated-subquery

这个问题有点是my previous one的后续问题。它也基于SQLZOO's "SELECT within SELECT tutorial"。这次是关于任务#8

首先,一个可接受的解决方案:

SELECT w1.name, w1.continent FROM world w1
WHERE w1.population > ALL(
SELECT w2.population*3 FROM world w2
WHERE w2.continent=w1.continent and w2.name<>w1.name)

这次相关查询在逻辑中根深蒂固。

此查询是否仍然可以合理重写JOIN?应该是吗?

2 个答案:

答案 0 :(得分:2)

所以任务8说:有些国家的人口是其邻国(在同一个大陆)的三倍以上。给各个国家和大陆。

我觉得有点不清楚。哪个是邻居?这是非洲大陆的所有国家吗?如果是,则下一个问题是我们是否与最小邻居或最大邻居进行比较。让我们说它是最大的邻居。然后查询将是这样的

select name, continent
  from world w1
 where w1.population > (select max(3*w2.population) 
                          from world w2
                         where w2.continent =  w1.continent
                           and w2.name      <> w1.name)

否则,如果它将是所有邻居的3倍,那么就是这个

select name, continent
  from world w1
 where w1.population > (select 3*sum(w2.population) 
                          from world w2
                         where w2.continent =  w1.continent
                           and w2.name      <> w1.name)

希望它有所帮助。

编辑:Oracle SQL手册(E26088-01)说明了所有功能:

  

将值与列表中的每个值进行比较或由查询返回。

示例:

SELECT * FROM employees
WHERE salary >=
ALL ( 1400, 3000)
ORDER BY employee_id;

首先进行聚合,然后进行比较,我们将其减少为一个比较。给定示例表中的结果是相同的。但针对所有国家的查询实际上可能会产生不同的结果。毕竟我必须说你的查询更好。如果你在一个大陆拥有1百万,3.5百万和11百万人口的国家,那么实际上第二个国家是第一个国家的3倍,第三个国家是第二个国家的3倍。我的查询只会比较第二个国家和第三个国家,但您的查询也会比较第一个国家和第二个国家。

答案 1 :(得分:1)

对于此特定查询,您需要每个大洲上的最大和第二大值。我会用窗口函数来处理它:

select w.continent,
       max(case when seqnum = 1 then w.name end) as name
from (select w.*, 
             row_number() over (partition by continent order by population desc) as seqnum
      from world w
     ) w
where seqnum in (1, 2)
group by continent
having max(case when seqnum = 1 then population end) > 3*max(case when seqnum = 2 then population end)

好的,我承认,考虑到问题的根源,这可能有点先进。

所以,这是一种使用连接而不是相关子查询的方法:

我认为以下是您的逻辑:

select w.name, w.continent
from world w join
     (SELECT w.continent, maxpopulation,
             max(case when population <> maxpopulation then population end) as secondmax
      FROM world w join
           (select continent, max(population) as maxpopulation
            from world
            group by continent
           ) c
           on w.continent = c.continent
      group by w.continent, maxpopulation
     ) wc
     on w.continent = wc.continent and w.population = maxpopulation
where population >= 3*secondmax

所以答案是&#34;是的,你可以在没有相关子查询的情况下做到这一点。&#34;在大多数常见情况下,您可以使用连接和分组重写相关子查询。

相关问题