Очень трудно понять этот запрос

Следующий запрос должен возвращать «моряков, забронировавших все лодки».

а вот код mySQL

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS 
    ((SELECT B.bid  
     FROM Boats B)
    Except
    (SELECT R.bid  
     FROM Reserves R
     WHERE R.sid = S.sid))

И я просто... не знаю, как это читать. Я понимаю, что подзапрос, который следует за "NOT EXISTS", должен возвращать идентификатор лодки (ставка) для всех записей в таблице Boats. Таким образом, следующий запрос Except должен возвращать идентификаторы лодок для всех лодок, которые были зарезервированы ... так что это означает, что если есть кто-то, кто зарезервировал все лодки, ничего не должно возвращаться, а это означает, что NOT EXISTS будет оцениваться как true, и это будет просто назовите имя этого моряка? Я думаю, что это последняя часть, которая меня смущает... как это в конечном итоге возвращает имя моряка?


person FrostyStraw    schedule 11.10.2015    source источник
comment
Я не знаю, поддерживает ли MySQL предложение EXCEPT.   -  person Strawberry    schedule 11.10.2015
comment
@Клубничка, это интересно. Мой профессор заставил нас загрузить сервер MySQL, чтобы попрактиковаться в выполнении SQL-запросов, но она дает нам примеры, отличные от MySQL (например, этот). Вздох.   -  person FrostyStraw    schedule 11.10.2015
comment
@shA.t Это запрос, который дал мне мой профессор. Я больше ищу... английский перевод того, что он делает, чем исправление для него... Я считаю, что подзапрос возвращает все идентификаторы лодок, которые НЕ были зарезервированы. Итак, когда я читаю НЕ СУЩЕСТВУЕТ, к чему применяется НЕ СУЩЕСТВУЕТ? Что не существует? Это говорит о том, что нужно найти несуществующее имя в таблице всех незарезервированных идентификаторов лодок? И если в этой таблице нет имен (только идентификаторы лодок), как она вообще возвращает ЛЮБЫЕ имена?   -  person FrostyStraw    schedule 12.10.2015


Ответы (2)


У нас есть несколько лодок, которые могут быть зарезервированы моряками. Моряки зарегистрированы, и мы их знаем. Итак, структура таблиц:

[Table: Boats]          [Table: Sailors]        [Table: Reserves]
+-----+--------+        +-----+----------+      +-----+-----+-----+
| bid | bname  |        | sid | sname    |      | rid | bid | sid |
+-----+--------+        +-----+----------+      +-----+-----+-----+
| 1   | Boat 1 |        | 1   | Sailor 1 |      | 1   | 1   | 1   |
| 2   | Boat 2 |        | 2   | Sailor 2 |      | 2   | 2   | 3   |
| 3   | Boat 3 |        | 3   | Sailor 3 |      +-----+-----+-----+
+-----+--------+        +-----+----------+

В приведенных выше данных, когда вам нужно знать, какие лодки не зарезервированы; вы можете использовать приведенный ниже запрос, который даст вам ставку => 3:

SELECT B.bid  FROM Boats B
EXCEPT
SELECT R.bid  FROM Reserves R;

И когда вам нужно знать, какие лодки (никогда) не забронированы моряком; вы можете использовать приведенный ниже запрос, который даст вам ставку => [1, 3] для sid = 3:

SELECT B.bid  FROM Boats B
EXCEPT
SELECT R.bid  FROM Reserves R  WHERE R.[sid] = 3;

И когда моряк зарезервирует все лодки, приведенный выше запрос не даст результата, поэтому NOT EXISTS(<above query>) будет верным. Теперь вы можете использовать приведенный выше запрос, чтобы найти моряков, которые резервируют все лодки следующим образом:

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS (
    SELECT B.bid  FROM Boats B
    EXCEPT
    SELECT R.bid  FROM Reserves R
    WHERE R.[sid] = S.[sid]);

Итак, если данные Reserves станут примерно такими:

 [Table: Reserves]
 +-----+-----+-----+
 | rid | bid | sid |
 +-----+-----+-----+
 | 1   | 1   | 1   |
 | 2   | 2   | 1   |
 | 3   | 3   | 1   |
 +-----+-----+-----+

Ваш запрос даст результат Sailor 1 ;).


Дополнительная информация:
EXCEPT возвращает отдельные строки из левого входного запроса, которые не выводятся правым входным запросом.
EXISTS: указывает подзапрос для проверки для существования строк.

person shA.t    schedule 12.10.2015
comment
собираюсь прочитать это, но в конце, когда вы определяете EXCEPT, не должно ли оно сказать, что возвращаются отдельные строки из левого входного запроса, которые ЯВЛЯЮТСЯ выведенными правым входным запросом? @shA.t - person FrostyStraw; 12.10.2015
comment
@FrostyStraw Это взято отсюда - person shA.t; 12.10.2015
comment
Хорошо, так что... является ли что-либо из следующего неправильным: НЕ СУЩЕСТВУЕТ ли применяется один за другим к каждой строке в матросах? Например, для sid = 1 он будет выполнять запрос внутри NOT EXISTS, и если строки не будут возвращены, он просто вернет имя моряка, соответствующего этому идентификатору? Затем он перейдет к sid = 2 (при условии, что несколько моряков могут зарезервировать лодку одновременно), и если ни одна строка не будет возвращена снова, будет возвращено имя моряка, соответствующее sid = 2, в противном случае он продолжит sid = 3 и так далее и тому подобное? @shA.t - person FrostyStraw; 12.10.2015
comment
Я могу сказать да; СУБД делает это так близко к этому; вы можете проверить проверку внутреннего выбора EXISTS, выполнив тест ручной установки значений для внешних значений (например, S. [sid]);). - person shA.t; 12.10.2015

Вы можете преобразовать sql, подзапрос

(SELECT B.bid  
 FROM Boats B)
Except
(SELECT R.bid  
 FROM Reserves R
 WHERE R.sid = S.sid)

должно быть таким же, как

(SELECT B.bid  
 FROM Boats B
 WHERE B.sid <> S.sid)

Если вы замените часть в основном sql, вы получите

SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS 
(SELECT B.bid  
 FROM Boats B
 WHERE B.sid <> S.sid)

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

person AlexN    schedule 11.10.2015