Требуемый вам реляционный оператор - это полуразница a.k.a. antijoin .
В большинстве продуктов SQL отсутствует явный оператор или ключевое слово semi-join. В стандартном SQL-92 его нет (у него есть предикат MATCH (subquery)
semi-join, но, хотя соблазнительно думать иначе, семантика для NOT MATCH (subquery)
не такая же, как для полуразличия; FWIW - действительно реляционный язык Tutorial D успешно использует половинную разницу NOT MATCHING
).
Полуразличие, конечно, может быть записано с использованием других предикатов SQL. Наиболее часто встречаются: внешнее объединение с проверкой нулей в предложении WHERE
, за которым следуют EXISTS
или IN (subquery)
. Использование EXCEPT
(эквивалентно MINUS
в Oracle) - это еще один возможный подход, если ваш продукт SQL поддерживает его и снова в зависимости от данных (в частности, когда заголовки двух таблиц совпадают).
Лично я предпочитаю использовать EXISTS
в SQL для полуразностного соединения, потому что предложения объединения находятся ближе друг к другу в написанном коде и не приводят к проекции на объединенную таблицу, например,
SELECT *
FROM ads
WHERE NOT EXISTS (
SELECT *
FROM assigned_ads
WHERE ads.ID = assigned_ads.ID
);
Как и в случае IN (subquery)
(то же самое для подхода с внешним соединением), вам нужно быть особенно осторожным, если предложение WHERE
в подзапросе содержит пустые значения (подсказка: если предложение WHERE
в подзапросе оценивает UNKNOWN из-за наличие нулей, тогда оно будет принудительно установлено как ЛОЖНОЕ к EXISTS
, что может привести к неожиданным результатам).