Использование информации из одной таблицы, чтобы найти, существует ли информация в другой таблице - PullRequest
2 голосов
/ 12 октября 2011

У меня есть 2 таблицы:

объявления:

+------+---------------+
|  ID  |  Name         |
+------+---------------+
| 1    |   Item 1      |
| 2    |   Item 2      |
| 3    |   Item 3      |
| 4    |   Item 4      |
| 5    |   Item 5      |
+------+---------------+

assign_ads:

+------+-----------+--------------+
|  ID  |   ad_id   |  location    |
+------+-----------+--------------+
|  1   |    3      |  place 1     |
|  2   |    2      |  place 2     |
|  3   |    1      |  place 3     |
+------+-----------+--------------+

Как видите; Все объявления 1, 2 и 3 назначены определенному местоположению. Мне нужен запрос, который получает все строки в таблице ads, которые не назначены в таблице assigned_ads

Ответы [ 5 ]

4 голосов
/ 12 октября 2011

Для этого вам нужно использовать левое внешнее соединение, как показано ниже:

SELECT * 
FROM ads a
LEFT JOIN assigned_ads aa ON a.ID = aa.ad_id
WHERE aa.location IS NULL
1 голос
/ 13 октября 2011

Требуемый вам реляционный оператор - это полуразница 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, что может привести к неожиданным результатам).

1 голос
/ 12 октября 2011

Вы также можете использовать оператор NOT EXISTS:

SELECT * 
FROM ads a
WHERE NOT EXISTS
(SELECT * FROM assigned_ads aa WHERE a.ID = aa.ad_id)
0 голосов
/ 12 октября 2011

просто пользователь оставил запрос на присоединение и сопоставил левый идентификатор таблицы с нулем.Ваш запрос должен выглядеть следующим образом

select * from ads ad left join assigned_ad a_ad ON a_ad.ad_id = ad.id where a_ad.id is null

Для получения дополнительной информации о левом соединении обратитесь к здесь

0 голосов
/ 12 октября 2011

попробуйте это:

SELECT * 
FROM ads a
WHERE a.id NOT IN (SELECT ad_id FROM assigned_ads)
...