Как выбрать все записи из одной таблицы, которые не существуют в другой таблице?

470

table1 (идентификатор, имя)
table2 (идентификатор, имя)

Запрос:

SELECT name   
FROM table2  
-- that are not in table1 already
г-хозяин
источник

Ответы:

844
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

Q : что здесь происходит?

A : Концептуально, мы выбираем все строки table1для каждой строки, в которой мы пытаемся найти строку table2с одинаковым значением для nameстолбца. Если такой строки нет, мы просто оставляем table2часть нашего результата пустой для этой строки. Затем мы ограничиваем наш выбор, выбирая только те строки в результате, где соответствующая строка не существует. Наконец, мы игнорируем все поля из нашего результата, кроме nameстолбца (который, как мы уверены, существует, из table1).

Хотя это может быть не самый производительный метод, возможный во всех случаях, он должен работать практически в каждом механизме баз данных, когда-либо пытающихся реализовать ANSI 92 SQL

Kris
источник
16
@ z-boss: он также наименее производительный на SQL Server: объяснение
xtended.com/2009/09/15/…
7
@BunkerBoy: соединение слева позволяет не существовать строкам справа, что не влияет на включение рядов слева. Внутреннее соединение требует наличия строк слева и справа. То, что я делаю здесь, это применяет некоторую логику, чтобы в основном получить обратный выбор внутреннего соединения.
Крис
2
О боже, это помогло очень легко визуализировать, другие назвали это 5 разными способами, но это помогло. все просто: сначала вы получаете левое соединение, все в A и все в B, что соответствует A. Но как это происходит в левых полях, которые не объединяются, просто равны нулю. Тогда вы говорите, хорошо, я только хочу, чтобы это ноль. Таким образом, теперь у вас есть все строки в A, у которых не было совпадения в B
Мухаммед Умер
7
Следует отметить, что это решение (принятое и проголосованное) является единственным, я думаю, оно может быть отредактировано для сценария, когда в игру вступает более одного поля. В частности, я возвращаю поле, поле 2, поле 3 из таблицы 1, где комбинация поля ad field2 отсутствует во второй таблице. За исключением изменения объединения в этом ответе, я не вижу способа сделать это с некоторыми другими «более эффективными ответами», о которых
говорится
1
Просто убедитесь, что вы используете "WHERE t2.name IS NULL", а не "AND t2.name IS NULL", потому что "и" не дадут правильных результатов. Я не очень понимаю, почему, но это факт, я проверял это.
user890332
236

Вы можете сделать

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

или

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

Посмотрите этот вопрос для 3 методов для достижения этой цели

froadie
источник
38
Это невероятно медленно с большими объемами данных.
Lightbulb1
Да, действительно, это очень медленно
sirus
Не должно быть «из таблицы1» в подзапросе запроса «не существует».
гончая
Очень смущен тем, как это вызвало столько голосов. Мне очень трудно придумать причину, чтобы когда-либо использовать это, когда есть подход к этой проблеме, который невероятно быстрее с примерно таким же количеством нажатий клавиш.
searchengine27
Это сработало для меня .. Спасибо
Thameem
81

У меня недостаточно очков репутации, чтобы проголосовать за второй ответ. Но я должен не согласиться с комментариями на верхний ответ. Второй ответ:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

Является ли FAR более эффективным на практике. Я не знаю почему, но я работаю с 800k + записями, и разница огромна с преимуществом, полученным во втором ответе, опубликованном выше. Просто мои 0,02 доллара

Тан Резаи
источник
31
В запросе NOT IN подзапрос выполняется только один раз, в запросе EXISTS подзапрос выполняется для каждой строки
Carrick
2
Вы великолепны :), таким образом, я конвертирую свой 25-секундный запрос, используя левое соединение, в 0,1 секунды
Бассем Шахин
3
ответы не в определенном порядке, поэтому второй ответ не означает, что вы думали, что это значит.
38

Это чистая теория множеств, которой вы можете достичь с помощью minusоперации.

select id, name from table1
minus
select id, name from table2
зима
источник
Как вы думаете, это гораздо эффективнее, чем левое соединение?
UHS
Должен быть. Команда минус предназначена именно для этой ситуации. Конечно, единственный способ оценить какой-либо конкретный набор данных - это попробовать оба варианта и посмотреть, какой из них работает быстрее.
зима
9
В T-SQL оператором set является «кроме». Это очень удобно для меня и не вызвало замедления.
2
В SQLite оператор «минус» также «кроме».
лайфлай
MySQL не поддерживает оператор MINUS.
Мухаммед Азим
16

Остерегайтесь ловушек. Если поле Nameв Table1содержит NULLS вы в сюрпризы. Лучше это:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)
user4872693
источник
1
COALESCE> ISNULL (ISNULL - бесполезное дополнение T-SQL к языку, которое не делает ничего нового или лучше, чем COALESCE)
Kris
14

Вот что сработало лучше для меня.

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

Это было более чем в два раза быстрее, чем любой другой метод, который я пробовал.

боб
источник
Спасибо, это хорошо работает с большим количеством данных тоже! Но я просто интересуюсь термином «Кроме».
PatsonLeaner
7

Это работа для меня

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL
Дэвид Фози
источник
1

Смотрите запрос:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

Концептуально было бы: выборка соответствующих записей в подзапросе, а затем в основном запросе выборка записей, которые не находятся в подзапросе.

Джавахар
источник
0

Я собираюсь сделать репост (поскольку я еще не достаточно крутой, чтобы комментировать) в правильном ответе .... на тот случай, если кто-то еще подумает, что лучше объяснить.

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

И я видел синтаксис в FROM, нуждающийся в запятых между именами таблиц в mySQL, но в sqlLite казалось, что он предпочитает пробел.

Суть в том, что когда вы используете неверные имена переменных, это оставляет вопросы. Мои переменные должны иметь больше смысла. И кто-то должен объяснить, почему нам нужна запятая или нет запятой.

Адриан Рот
источник
0

Если вы хотите выбрать конкретного пользователя

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

tent_npkЯвляется первичным ключом пользователя

Fragmantedbin
источник