SQL в любом vs != Any

#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.