帮助我理解嵌套SELECT语句的这种特殊用法

时间:2011-05-24 22:07:10

标签: sql select nested

来自this网站:

表:

CREATE TABLE PilotSkills
(pilot_name CHAR(15) NOT NULL,
plane_name CHAR(15) NOT NULL,
PRIMARY KEY (pilot_name, plane_name));

CREATE TABLE Hangar
(plane_name CHAR(15) NOT NULL PRIMARY KEY);

查询:

SELECT DISTINCT pilot_name
  FROM PilotSkills AS PS1
  WHERE NOT EXISTS
       (SELECT *
          FROM Hangar
         WHERE NOT EXISTS
               (SELECT *
                  FROM PilotSkills AS PS2
                 WHERE (PS1.pilot_name = PS2.pilot_name)
                   AND (PS2.plane_name = Hangar.plane_name)));

我理解它用于(设置分区)的问题,包括将其描述为“这个机库中没有飞机我不能飞行!”的类比。我不明白的是这里的工作原理是什么,以及它如何结合起来做它所说的。

目前难以说明我的困难......


编辑:让我先问一下这样的事情,完全

SELECT DISTINCT pilot_name
  FROM PilotSkills
  WHERE NOT EXISTS
       (SELECT *
          FROM Hangar)

我想我在这里缺少一些基本的理解......

编辑:不相关,没有第三个嵌套的SELECT就没有意义,对吧?

3 个答案:

答案 0 :(得分:1)

最初作为次要评论,在这种情况下,选择*是过度的。您应该选择单个列或几列,但应避免拉出所有列,尤其是在子查询中,它们仅在查询期间使用而不在最终结果集中返回。也就是说,试图打破工作流程:

  1. 从PilotSkills中选择Pilot_Name - 我们最终对飞行员名称感兴趣。
  2. 不存在的地方(从机库中选择*) - 如果机库表中没有相关条目,我们只会检索飞行员。
  3. 不存在的地方(从PilotSkills中选择*) - 我们只会从外部查询中检索没有导航的Hangars。
  4. 将其描述为双重否定(来自另一个答案)是理解它的好方法。它可以更直接地实现。

答案 1 :(得分:1)

我们想要的是一个独特的飞行员名单,可以在悬挂的每架飞机上飞行。为了实现这一点,对于一个特定的飞行员来说,不存在他们无法飞行的飞机。因此,我们希望获得每个飞行员的所有飞机的列表,看看是否有一架飞机无法飞行。如果有一个(飞行员不能飞行),我们将其从列表中删除。无论谁离开,都可以悬挂在衣架上的所有飞机。

更正式地说,找到一个明确的飞行员名单,这样对于一个给定的飞行员来说,在这组飞机中没有一架飞机(衣架),这样飞机就不存在于给定飞行员技能的集合中

  

“找到一份独特的飞行员名单   名...“

Select Distinct pilot_name
From PilotSkills As PS1
...
  

“......对于一个特定的飞行员来说,那里   在该组中不存在飞机   飞机(衣架)......“

Select Distinct pilot_name
From PilotSkills As PS1
Where Not Exists    (
                    Select 1
                    From Hanger
  

“......这样飞机就不存在了   在给定飞行员的集合中   技巧“。

Select Distinct pilot_name
From PilotSkills As PS1
Where Not Exists    (
                    Select 1
                    From Hanger As H
                    Where Not Exists    (
                                        Select 1
                                        From PilotSkills As PS2
                                        Where PS2.pilot_name = PS1.pilot_name
                                            And PS2.plane_name = H.plane_name
                                        )
                    )

答案 2 :(得分:0)

从概念上讲,这只是一个双重否定。

  

选择那里的所有飞行员   在机库中不存在飞机   他们不能飞。

但是你似乎在询问查询本身的机制?它使用两级相关子查询。

如果我们将行数减少到最小量并添加一个额外的表以稍微简化说明(查询中的PilotSkills的外部实例仅用于获取Pilots列表)。然后查询看起来像

SELECT pilot_name
  FROM Pilots
  WHERE NOT EXISTS
       (SELECT *
          FROM Hangar
         WHERE NOT EXISTS
               (SELECT *
                  FROM PilotSkills 
                 WHERE (Pilots.pilot_name = PilotSkills.pilot_name)
                   AND (PilotSkills.plane_name = Hangar.plane_name)));

<强>飞行员

pilot_name 
===========
'Celko'    
'Higgins'  

<强>机库

plane_name
=============
'B-1 Bomber'
'F-14 Fighter'

<强> PilotSkills

pilot_name    plane_name
=========================
'Celko'    'F-14 Fighter'
'Higgins'  'B-1 Bomber'
'Higgins'  'F-14 Fighter'

如果你想知道哪些飞行员可以飞机库中的所有飞机那么

  1. 依次为每个Pilots.pilot_name
  2. 依次查看每个Hangar.plane_name
  3. 并检查PilotSkills
  4. pilot_name,plane_name中是否有相应的行

    如果步骤3为假,那么我们知道机库中至少有一架飞机无法飞行,我们可以停止处理Pilots行并进入下一行。如果步骤3为真,那么我们必须返回步骤2并检查机库中的下一个平面。如果我们完成处理机库中的所有飞机并且每个飞机在PilotSkills中都有相应的行,那么我们就知道这个飞行员可以飞行所有飞机。

    或者换句话说我们知道没有一个平面(因为我们已经检查过它们),PilotSkills表中没有匹配的行。