#sql
#sql
Вопрос:
У меня есть следующие таблицы:
Для студентов:
------ ---------
| Snum | Sname |
------ ---------
| S1 | Charles |
| S2 | Amy |
| S3 | John |
------ ---------
Курсы:
----- ------------
| cid | coursecode |
----- ------------
| C1 | CMPT222 |
| C2 | ASC111 |
----- ------------
Регистрация:
------ -----
| sid | cid |
------ -----
| S1 | C1 |
| S2 | C2 |
------ -----
В общем, у меня есть три студента, и двое из них зачислены.
Запрос таков: Найдите snum, которые не зарегистрированы:
SELECT DISTINCT S.snum
FROM Student S
WHERE S.snum! = any (SELECT E.snum FROM Enrolled E )
Этот запрос возвращает:
1
2
3
Что неверно.
Насколько я понимаю: для каждого кортежа во внешнем запросе ANY проверит, существует ли хотя бы один кортеж. если да, то он возвращает TRUE. Если мы используем !=, то он должен возвращать 3.
Чего мне не хватает?
Комментарии:
1. Вы говорите, что у вас есть три зачисленных студента, но, согласно таблице зачисления, зачислено только 2 студента: S1 и S2. Не могли бы вы, пожалуйста, уточнить
2. извините, опечатка. его два.
Ответ №1:
Это ваш запрос:
SELECT DISTINCT S.snum
FROM Student S
WHERE S.snum <> any (SELECT E.snum FROM Enrolled E )
В принципе, если подзапрос возвращает более одного значения, то условие всегда будет истинным. Почему? Что ж, подумайте, является ли возвращаемый набор 1
и 2
. Ну, если вы сравниваете значение с одним из этих, то условие всегда выполняется. Помните: 1 <> 2
. Итак, если значение совпадает с первым, оно не соответствует второму.
Есть простые способы исправить это. Например:
WHERE NOT (S.snum = any (SELECT E.snum FROM Enrolled E ))
Или:
WHERE S.snum NOT IN (SELECT E.snum FROM Enrolled E )
На самом деле, мне не нравится, NOT IN
потому что он по-разному обрабатывает NULL
значения. В этом случае я предпочитаю NOT EXISTS
.
Комментарии:
1. в <> any — почему он возвращает три кортежа (1,23).
2. @zephyr . . . Потому что условие всегда выполняется.
Ответ №2:
Поскольку оцениваемый вами предикат всегда имеет значение true, = any()
по крайней мере, одна эквивалентность. Не равно или <> any()
по крайней мере одно отсутствие эквивалентности. Из-за набора, возвращаемого вашим подзапросом, последний предикат всегда имеет значение true, а первый — просто значения s1
и s2
.
Обратите внимание, что, если ваш подзапрос вернет только одно значение, ваш выбор результата будет другим.
Длинное объяснение
Ваш подзапрос возвращает эти значения: s1
и s2
.Затем ваша СУБД переходит строка за строкой, вычисляя предикат. Затем,
s1
<> s1
-> false
s1
<> s2
-> true
Вычисление предиката, true
из any()
за.
Следующее значение,
s2
<> s1
-> true
Вычисление предиката true
… Третье значение:
s3
<> s1
-> true
Обратите внимание, что, some()
и any()
являются эквивалентными предложениями.
Думайте о any()
как о or
шлюзе. Каждый раз, когда найдено значение true (входные данные), выходные данные являются true.
Комментарии:
1. @zephyr Тогда примите ответ, чтобы мы закрыли тему. Я рекомендую использовать
<>
вместо!=
, поскольку<>
это стандартный sql и!=
является нестандартным и, следовательно, не является обязательной реализацией rdbms.