当前位置: 首页 > 知识库问答 >
问题:

这个self join是如何工作的?

乐正烨熠
2023-03-14

这是来自SQLZOO.NET的问题

+-------------+-----------+---------+
|    name     | continent |  area   |
+-------------+-----------+---------+
| Afghanistan | Asia      | 652230  |
| Albania     | Europe    | 2831741 |
| Algeria     | Africa    | 28748   |
| ...         | ...       | ...     |
+-------------+-----------+---------+
SELECT continent, name, area 
FROM world x
WHERE area >= ALL (SELECT area 
                   FROM world y
                   WHERE y.continent=x.continent
                   AND area>0)
+-------------+-----------+--------+
| continent   |   name    |  area  |
+-------------+-----------+--------+
|Africa       | Algeria   | 2381741|
|Oceania      | Australia | 7692024|
|South America| Brazil    | 8515767|
|North America| Canada    | 9984670|
|Asia         | China     | 9596961|
|Caribbean    | Cuba      |  109884|
|Europe       | France    |  640679|
|Eurasia      | Russia    |17125242|
+-------------+-----------+--------+

共有1个答案

戚学
2023-03-14

为了解释,我假设一个只有5个国家的世界表格如下:

Algeria      2381741
Australia    7692024
South Africa 1221037
New Zealand   268021
/*And to make it a little interesting:*/
Algeria Twin 2381741

子查询与基查询的每一行匹配,每次匹配1。这就是所谓的相关子查询。虽然相关的子查询工作良好,但通常认为它们是危险的,因为如果优化器不能找出更有效的等效结构,它们的性能特性就会很差。

下表说明了如何计算数据的逻辑视图。请注意,数据库的查询引擎可能能够在内部将计划转换为数学上等价的东西,但效率要高得多。

+-------------+--------------+--------+
| continent   |   name       |  area  |
+-------------+--------------+--------+
|Africa       | Algeria      | 2381741| >= ALL( /*y.continent='Africa'*/
                                               2381741, /*Alegria*/
                                               1221037, /*South Africa*/
                                               2381741) /*Alegria Twin*/
|Oceania      | Australia    | 7692024| >= ALL( /*y.continent='Oceania'*/
                                               7692024, /*Australia*/
                                               268021)  /*New Zealand*/
|Africa       | South Africa | 1221037| >= ALL( /*y.continent='Africa'*/
                                               2381741, /*Alegria*/
                                               1221037, /*South Africa*/
                                               2381741) /*Alegria Twin*/
|Oceania      | New Zealand  |  268021| >= ALL( /*y.continent='Oceania'*/
                                               7692024, /*Australia*/
                                               268021)  /*New Zealand*/
|Africa       | Algeria Twin | 2381741| >= ALL( /*y.continent='Africa'*/
                                               2381741, /*Alegria*/
                                               1221037, /*South Africa*/
                                               2381741) /*Alegria Twin*/
+-------------+--------------+--------+
WHERE area = ( SELECT MAX(y.area)
               FROM   world y
               WHERE  y.continent=x.continent)
WHERE area = ( SELECT y.area
               FROM   world y
               WHERE  y.continent=x.continent
               ORDER BY y.area DESC LIMIT 1)

但是,要小心下面这些看起来是等价的,但实际上并非如此。

/* The problem here is that only 1 Algeria will happen to be 
   first in the sub-query. Meaning 1 row will be missing from 
   the final result set. */
WHERE name = ( SELECT y.name
               FROM   world y
               WHERE  y.continent=x.continent
               ORDER BY y.area DESC LIMIT 1)

最后,我提到相关的子查询可能会有性能问题。因此,如果可以的话,通常最好考虑将相关的子查询改写为直接连接到FROM子句中的子查询的子查询。例如。

SELECT  x.contient, x.name, x.area
FROM    world x
        INNER JOIN (
            SELECT MAX(y.area) as max_area, y.continent
            FROM   world y
            GROUP BY y.continent
        ) z ON
            x.continent = z.continent
        AND x.area = z.max_area
 类似资料:
  • 我试图了解mysql查询在GROUP BY和不使用GROUP BY的情况下是如何工作的。 假设我有一个FILM_ACTORS表,其中每个ACTOR_ID都有一个相应的film_id。于是同一个演员参演了N部不同的电影。 我想选出参与20部电影的演员: 这个查询起作用,并返回参与20部电影的actor_id。但如果我只是: 为什么该查询仅在我将其等于film_actor表(5463)的大小时才返回值

  • Kotlin定义了自己的类: 该类的实例是通过中定义的内联函数构造的: null 我认为在编译之前必须进行某种代码预处理。 请随意用一个更贴切的标题编辑这个问题。

  • 我正在阅读《实用恶意软件分析》一书,其中出现了以下示例代码: 作者接着说: 返回的COM对象将存储在堆栈中IDA Pro标记为ppv的变量中,如图所示。 我的问题是,这是为什么?既然我们做了一个mov eax,[esp 24h ppv],这难道不是将[esp 24h ppv]内部的数据移动到eax并覆盖返回值,而不是将返回值存储在变量中吗?我认为在Intel格式中,mov操作数1、操作数2总是将第

  • 我在一本书《做二进制搜索》中看到了这个方法,但无论我怎么尝试,我都无法理解它是如何工作的。有人能确切地向我解释一下它是如何工作的吗? 这本书的解释无助于: 这个想法是在我们靠近目标元素时跳跃并减慢速度。变量k和b包含数组中的位置和跳跃长度。如果数组包含元素x,搜索后x的位置将在变量k中。该算法的时间复杂度为O(log n),这是因为对每个跳转长度而言,同时循环中的代码最多执行两次。 我不明白的是k

  • 我正在阅读关于从内部类继承的内容,我一直在努力理解下面的代码是如何工作的: 据我所知,关键字Super指的是超类,Super()指的是它没有参数构造函数。在外层类的情况下,超类是Object类。 我想了解一下,这段代码是如何工作的。 为什么Object类的实例化使扩展内部类成为可能? 创建Object类实例与创建外层类对象有什么关系? 删除包含"o.super();"的行会导致错误: java:包

  • 下面的代码片段检查给定的数字是否是素数。有人能给我解释一下为什么会这样吗?这段代码在Java考试的学习指南中。