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

问题描述

| 从此站点: 表格:
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不会有意义,对吧?     

解决方法

我们想要的是一个可以在衣架上的每个飞机上飞行的飞行员列表。为了做到这一点,对于给定的飞行员,不可能存在他们无法飞行的飞机。因此,我们想要获取每个飞行员的所有飞机的清单,并查看是否有飞机无法飞行。如果有一个(飞行员无法飞行),我们将其从列表中删除。剩下的任何人都可以在衣架上驾驶所有飞机。 更正式地说,找到飞行员姓名的唯一列表,以便对于给定的飞行员,在飞机组中不存在飞机(Hanger),从而在给定飞行员的技能组中不存在该飞机。   找到飞行员的不同清单   名字... \“
Select Distinct pilot_name
From PilotSkills As PS1
...
  \“ ...这样,对于给定的飞行员,   在的集合中不存在平面   飞机(Hanger)... \“
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
                                        )
                    )
    ,最初,作为次要评论,Select *在这种情况下是过大的。您应该选择一列或两列,但应避免拉所有列,尤其是在子查询中,这些子查询仅在查询期间使用,而不在最终结果集中返回。也就是说,尝试分解工作流程: 从PilotSkills中选择Pilot_Name-我们最终对飞行员名称感兴趣。 不存在的地方(从机库中选择*)-如果机库表中没有与飞行员相关的条目,我们将只检索飞行员。 不存在的地方(从飞行员技能中选择*)-我们只会从外部查询中检索没有飞行员的机库。 将其描述为双重否定(来自其他答案)是理解它的好方法。它可能可以更直接地实现。     ,从概念上讲,这只是双重否定。   选择那里所有的飞行员   在机库中不存在飞机   他们不能飞。 但是似乎您在询问查询本身的机制?它使用两个级别的相关子查询。 如果我们将行数减少到最小数量并添加一个额外的表以稍微简化说明(查询中PilotSkills的外部实例仅用于获取飞行员列表)。然后查询看起来像
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\'
飞行员技能
pilot_name    plane_name
=========================
\'Celko\'    \'F-14 Fighter\'
\'Higgins\'  \'B-1 Bomber\'
\'Higgins\'  \'F-14 Fighter\'
如果您想知道哪些飞行员可以驾驶飞机库中的所有飞机,那么 依次每each10ѭ 依次看每个ѭ11 并检查
PilotSkills
中是否有对应于row13ѭ的行 如果第3步为假,则我们知道机库中至少有一个飞机无法飞行,因此我们可以停止处理“ 14”行并转到下一个。如果步骤3是正确的,那么我们必须返回步骤2并检查机库中的下一架飞机。如果我们完成了对机库中所有飞机的处理,并且每架飞机在ѭ12中都有对应的一行,那么我们知道该飞行员可以驾驶所有飞机。 或者换种说法,我们知道在
PilotSkills
表中不存在不存在匹配行的平面(因为我们已经检查了所有平面)。