Помогите мне понять это конкретное использование вложенных операторов SELECT - PullRequest
5 голосов
/ 25 мая 2011

Из этого сайта:

Таблица:

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 ]

1 голос
/ 25 мая 2011

В качестве незначительного комментария изначально, Select * в этой ситуации излишен. Вы должны выбрать один столбец или несколько столбцов, но следует избегать извлечения всех столбцов, особенно в подзапросах, где они используются только во время запроса и не возвращаются в окончательном наборе результатов. Тем не менее, чтобы попытаться разбить рабочий процесс:

  1. Выберите Pilot_Name из PilotSkills - нас интересуют имена пилотов.
  2. Где не существует (выберите * Из ангара) - Мы собираем пилотов, только если для них нет соответствующей записи в таблице ангара.
  3. Где не существует (выберите * Из PilotSkills) - мы собираем только ангары, у которых нет пилота из внешнего запроса.

Описание его как двойного отрицания (из другого ответа) - отличный способ понять это. Вероятно, это может быть достигнуто более напрямую.

1 голос
/ 25 мая 2011

То, что мы хотим, это четкий список пилотов, которые могут летать на каждом самолете в ангаре. Для того, чтобы это было правдой, для данного пилота не может существовать самолет, на котором он не может летать. Итак, мы хотим получить список всех самолетов для каждого пилота и посмотреть, есть ли один, на котором они не могут летать. Если он есть (пилот не может летать), мы удаляем их из списка. Кто бы ни остался, он может управлять всеми самолетами в вешалке.

Говоря более формально, найдите отдельный список имен пилотов, так что для данного пилота не существует плоскости в наборе самолетов (Hanger), так что самолет не существует в наборе навыков данного пилота .

"найти внятный список пилотов имена ... "

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
                                        )
                    )
0 голосов
/ 25 мая 2011

Концептуально это просто двойной минус.

Выберите всех пилотов, для которых в ангаре не существует самолета, на котором они не могут летать.

Нокажется, вы спрашиваете о механике самого запроса?Он использует два уровня коррелированного подзапроса.

Если уменьшить число строк до минимальной суммы и добавить дополнительную таблицу, чтобы немного упростить объяснение (внешний экземпляр 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'

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 соответствующая строка для этого pilot_name,plane_name

Если шаг 3 ложный, то мы знаем, чтов ангаре есть хотя бы один самолет, пилот не может летать, и мы можем прекратить обработку этого Pilots ряда и перейти к следующему.Если шаг 3 верен, тогда мы должны вернуться к шагу 2 и проверить следующую плоскость в ангаре.Если мы закончим обработку всех самолетов в ангаре и для каждого из них будет соответствующая строка в PilotSkills, то мы знаем, что этот пилот может летать на всех самолетах.

Или, говоря иначе, мы знаем, что не существует плоскости (как мы их все проверили), для которой не существует подходящей строки в таблице PilotSkills.

...