Как работают операторы SQL EXISTS?
Я пытаюсь изучить SQL, и я с трудом понимаю инструкции EXISTS. Я наткнулся на эту цитату о "существует" и ничего не понимаю:
Используя оператор exist, ваш подзапрос может возвращать ноль, один или несколько строк, а условие просто проверяет, вернул ли подзапрос какие-либо строки. Если вы посмотрите на предложение select в подзапросе, вы увидите, что он состоит из одного литерала (1); поскольку условие в содержащем запросе требует только знать, сколько строк было возвращено, фактические данные, полученные в подзапрос, не имеют значения.
Я не понимаю, как внешний запрос знает, какую строку подзапрос проверяет? Например:
SELECT *
FROM suppliers
WHERE EXISTS (select *
from orders
where suppliers.supplier_id = orders.supplier_id);
Я понимаю, что если идентификатор из таблицы поставщика и заказов совпадает, подзапрос вернет значение true, и все столбцы из соответствующей строки в таблице поставщиков будут выведены. То, что я не получаю, - это то, как подзапрос сообщает, какая конкретная строка (скажем, строка с идентификатором поставщика 25) должна быть напечатана, если возвращается только true или false.
Мне кажется, что между внешним запросом и подзапросом нет никакой связи.
Ответы
Ответ 1
Подумайте об этом так:
Для строки "каждая" из Suppliers
проверьте, существует ли строка в таблице Order
, соответствующая условию Suppliers.supplier_id
(это происходит из строки "Внешний запрос" ) = Orders.supplier_id
. Когда вы найдете первую совпадающую строку, остановитесь прямо там - WHERE EXISTS
выполнено.
Магическая связь между внешним запросом и подзапросом заключается в том, что Supplier_id
передается из внешнего запроса в подзапрос для каждой оцениваемой строки.
Или, другими словами, подзапрос выполняется для каждой строки таблицы внешнего запроса.
Это НЕ похоже, что подзапрос выполняется в целом и получает "true/false", а затем пытается сопоставить это условие "true/false" с внешним запросом.
Ответ 2
Мне кажется, что между внешним запросом и подзапросом нет никакой связи.
Как вы думаете, что делает предложение WHERE в примере EXISTS? Как вы пришли к такому выводу, когда ссылка SUPPLIERS не содержится в предложениях FROM или JOIN в предложении EXISTS?
EXISTS оценивает значение TRUE/FALSE и выходит из TRUE в первом совпадении критериев - поэтому он может быть быстрее, чем IN
. Также имейте в виду, что предложение SELECT в EXISTS игнорируется - IE:
SELECT s.*
FROM SUPPLIERS s
WHERE EXISTS (SELECT 1/0
FROM ORDERS o
WHERE o.supplier_id = s.supplier_id)
... должен ударить деление нулевой ошибкой, но это не произойдет. Предложение WHERE является наиболее важной частью предложения EXISTS.
Также имейте в виду, что JOIN не является прямой заменой для EXISTS, потому что будут дублированные родительские записи, если имеется более одной дочерней записи, связанной с родителем.
Ответ 3
Вы можете создавать идентичные результаты с помощью JOIN
, EXISTS
, IN
или INTERSECT
:
SELECT s.supplier_id
FROM suppliers s
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o
ON o.supplier_id = s.supplier_id
SELECT s.supplier_id
FROM suppliers s
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id)
SELECT s.supplier_id
FROM suppliers s
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o)
SELECT s.supplier_id
FROM suppliers s
INTERSECT
SELECT o.supplier_id
FROM orders o
Ответ 4
Если у вас есть предложение where, которое выглядит так:
WHERE id in (25,26,27) -- and so on
вы можете легко понять, почему некоторые строки возвращаются, а некоторые нет.
Когда предложение where выглядит так:
WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);
это просто означает: вернуть строки, которые имеют существующую запись в таблице заказов с тем же идентификатором.
Ответ 5
EXISTS означает, что в подзапросе возвращается хотя бы одна строка, что и есть на самом деле. В этом случае это коррелированный подзапрос, потому что он проверяет поставщик_ид внешней таблицы на имя поставщика_ид внутренней таблицы. Этот запрос говорит, по сути:
ВЫБРАТЬ всех поставщиков
Для каждого идентификатора поставщика см., Существует ли заказ для этого поставщика
Если поставщик отсутствует в таблице заказов, удалите поставщика из результатов
ВОЗВРАТИТЕ всех поставщиков, у которых есть соответствующие строки в таблице заказов.
Вы можете сделать то же самое в этом случае с INNER JOIN.
SELECT suppliers.*
FROM suppliers
INNER
JOIN orders
ON suppliers.supplier_id = orders.supplier_id;
Комментарий Ponies правильный. Вам нужно будет группировать с этим соединением или выбрать отдельный в зависимости от данных, которые вам нужны.
Ответ 6
То, что вы описываете, - это так называемый запрос с коррелированный подзапрос.
(В общем) это то, чего вы должны избегать, написав запрос, используя вместо этого соединение:
SELECT suppliers.*
FROM suppliers
JOIN orders USING supplier_id
GROUP BY suppliers.supplier_id
В противном случае подзапрос будет выполняться для каждой строки во внешнем запросе.