Почему этот SQL-код не работает с использованием простого предиката в конструкции WHERE EXISTS?

#mysql #sql

Вопрос:

Я работаю над образцом базы данных, чтобы изучить SQL как часть класса. Одной из задач было «Перечислить имена сотрудников, которые являются менеджерами, использующими EXISTS». (Я уже выполнил задание, так что можно получить ответ здесь).

Я изначально использовал это:

 SELECT `FIRSTNAME`
     , `MIDINIT`
     , `LASTNAME` 
  FROM `emp` 
 WHERE EXISTS (SELECT * FROM `emp` WHERE `JOB`='MANAGER')
 

Однако это просто не сработало бы.

Он продолжал показывать имена ВСЕХ сотрудников в emp таблице вместо 7, где JOB = «МЕНЕДЖЕР».

Вот что самое странное.

Когда я просто бегу

 (SELECT * FROM `emp` WHERE `JOB`='MANAGER')
 

он работает, чтобы показать только 7 строк, в которых сотрудники являются менеджерами.
результаты показывают только строки, где JOB = «МЕНЕДЖЕР»

Итак, почему он не работает как предикат WHERE EXISTS?

Чтобы заставить его работать, мне пришлось сделать следующее: ВЫБЕРИТЕ FIRSTNAME , MIDINIT , LASTNAME emp ОТКУДА СУЩЕСТВУЕТ (ВЫБЕРИТЕ * dept ОТКУДА emp . EMPNO = dept . MGRNUMBER ) Мне пришлось сравнить EMPNO в emp таблице с номером MGRNUMBER в dept таблице. Я не понимаю, почему мне пришлось перейти к другой таблице для сравнения значений.

Комментарии:

1. EXISTS нужен коррелированный подзапрос, чтобы иметь смысл. Как и сейчас, вы либо получите все строки (если существует строка, где JOB = «МЕНЕДЖЕР»), либо вообще никаких строк (если такой строки не существует).

2. Да, именно это и происходило-я получал все подряд. Я думал, что он соберет всю информацию из подзапроса, а затем выполнит основной запрос по подзапросу. Это не работает таким образом?

Ответ №1:

Ваш первоначальный запрос:

 SELECT `FIRSTNAME`
     , `MIDINIT`
     , `LASTNAME` 
  FROM `emp` 
 WHERE EXISTS (SELECT * FROM `emp` WHERE `JOB`='MANAGER')
 

…работает вот так. Для каждой строки, найденной в таблице, он проверяет предложение WHERE, которое ищет наличие любых строк с заданием = «МЕНЕДЖЕР». Он находит некоторые, поэтому включает строку. Затем он получает следующую строку и повторяет ту же проверку (которая проходит), чтобы включить следующую строку. Он повторяется для каждой строки и, таким образом, включает все строки в таблице.

Ответ @GenYMaverick-это один из способов использования существующего, но я бы не стал использовать его в производстве. Я бы использовал запрос, который вы придумали, потому что это самый простой, естественный и, вероятно, самый эффективный способ сделать это. (Я также надеюсь, что оптимизатор запросов был достаточно хорош, чтобы свести запрос @GenYMaverick к вашему; логически они одинаковы.)

Ответ №2:

Этот запрос должен решить вашу проблему:

Вам не нужно обращаться к другой таблице.

Операция EXISTS — это оператор, который проверяет, существует ли что-либо в подзапросе или нет. Он возвращает значение TRUE, если есть совпадение.

Поэтому, если вы хотите использовать только таблицу emp, вам необходимо подключить запросы внутри подзапроса с помощью EMPNO.

В моем примере я сделал это, объявив таблицу emp в основном запросе как emp1, а в подзапросе как emp2. Это делает возможным поиск наличия EMPNO в подзапросе.

 SELECT 
     FIRSTNAME,
     MIDINIT,
     LASTNAME 
FROM emp emp1 
WHERE EXISTS ( SELECT * 
               FROM emp emp2 
               WHERE emp1.EMPNO = emp2.EMPNO 
                 AND emp2.JOB='MANAGER' );
 

Комментарии:

1. Я достаточно новичок в SQL, чтобы не понимать здесь emp1 или emp2. Я предполагаю, что это означало бы создание новых таблиц, которые являются копиями исходной таблицы?

2. @mdign002 Я не понимаю, emp1 или emp2 -это псевдонимы. Временная таблица для каждого запроса копирует имена, чтобы определить, какой столбец таблицы используется в каждом выражении. Необходимо в состоянии WHERE emp1.EMPNO = emp2.EMPNO