我正在浏览SQLZOO“SELECT within SELECT tutorial”,这是完成工作的一个查询(任务 7 )
世界(名称,大陆,地区,人口,国内生产总值)
SELECT w1.name, w1.continent, w1.population
FROM world w1
WHERE 25000000 >= ALL(SELECT w2.population FROM world w2 WHERE w2.continent=w1.continent)
我的问题是关于此类查询的有效性。子查询将针对主查询的每一行(国家/地区)运行,从而反复重新填充给定大陆的ALL列表。
答案 0 :(得分:3)
首先,您需要了解oracle如何转换此查询以进行评估。
SELECT w1.name
, w1.continent
, w1.population
FROM world w1
WHERE 25000000 >= ALL(SELECT w2.population
FROM world w2
WHERE w2.continent=w1.continent
);
现在,优化器将使用ALL比较运算符后跟子查询的条件转换为使用ANY比较运算符和补充比较运算符的等效条件
SELECT w1.name
, w1.continent
, w1.population
FROM world w1
WHERE NOT(25000000 < ANY (SELECT w2.population
FROM world w2
WHERE w2.continent=w1.continent)
);
然后,优化器会使用ANY比较运算符转换条件的规则进一步将第二个查询转换为以下查询,然后是相关子查询:
SELECT w1.name
, w1.continent
, w1.population
FROM world w1
WHERE
NOT EXISTS (SELECT w2.population
FROM world w2
WHERE w2.continent=w1.continent
AND 25000000 < w2.population
);
这是我从oracle来源Link
取的对于你的问题:
答案 1 :(得分:1)
您可以简化此操作,而无需扫描表格两次:
select a.name, a.continent, a.population, a.max_pop
from (select w1.name, w1.continent, w1.population,
max(w1.population) over (partition by w1.continent) max_pop
from world w1
) a
where 25000000 >= a.max_pop;
答案 2 :(得分:1)
如果要在没有相关子查询的情况下重写查询,可以采用以下方法:
SELECT w1.name, w1.continent, w1.population
FROM world w1
JOIN
( SELECT continent, MAX(population) AS max_population
FROM world
GROUP BY continent
) c
ON c.continent = w1.continent
WHERE 25000000 >= c.max_population ;
我并不暗示这会更快。 Oracle的优化器非常好,这是一个简单的整体查询,但是你编写它。这是另一种简化:
SELECT w1.name, w1.continent, w1.population
FROM world w1
JOIN
( SELECT continent
FROM world
GROUP BY continent
HAVING MAX(population) <= 25000000
) c
ON c.continent = w1.continent ;