ВНИМАНИЕ О РЕШЕНИЯХ:
МНОГИЕ СУЩЕСТВУЮЩИЕ РЕШЕНИЯ ДАЮТ НЕПРАВИЛЬНЫЙ ВЫХОД, ЕСЛИ СТРОКИ НЕ УНИКАЛЬНЫ
Если вы являетесь единственным человеком, создающим таблицы, это может быть неактуально, но несколько решений будут давать различное количество выходных строк из рассматриваемого кода, когда одна из таблиц может не содержать уникальных строк.
ПРЕДУПРЕЖДЕНИЕ О ЗАЯВЛЕНИИ ЗАДАЧИ:
В НЕСКОЛЬКИХ КОЛОННАХ НЕ СУЩЕСТВУЕТ, ВНИМАТЕЛЬНО ПУНИТЕ, ЧТО ВЫ ХОТИТЕ
Когда я вижу вход с двумя столбцами, я могу представить, что это означает две вещи:
- Значения столбца a и столбца b появляются в другой таблице независимо
- Значения столбца a и столбца b появляются в другой таблице вместе в одной строке
Сценарий 1 довольно тривиален, просто используйте два оператора IN.
В соответствии с большинством существующих ответов, я настоящим предоставляю обзор упомянутых и дополнительных подходов для Сценария 2 (и краткое суждение):
EXISTS (Безопасный, рекомендуется для SQL Server)
Согласно @mrdenny, EXISTS звучит именно так, как вы ищете, вот его пример:
SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2
WHERE T1.a=T2.a and T1.b=T2.b)
LEFT SEMI JOIN (Безопасно, рекомендуется для диалектов, которые его поддерживают)
Это очень краткий способ присоединения, но, к сожалению, большинство диалектов SQL, включая SQL-сервер, в настоящее время не поддерживают его.
SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b
Несколько операторов IN (безопасно, но остерегайтесь дублирования кода)
Как уже упоминалось @cataclysm, использование двух операторов IN также может помочь, возможно, даже превзойдет другие решения. Тем не менее, вы должны быть очень осторожны с дублированием кода. Если вы когда-нибудь захотите выбрать из другой таблицы или изменить инструкцию where, это увеличит риск того, что вы создадите несоответствия в своей логике.
Основное решение
SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)
Решение без дублирования кода (я считаю, что это не работает в обычных запросах SQL Server)
WITH mytmp AS (SELECT a, b FROM T2 WHERE something);
SELECT * from T1
WHERE a IN (SELECT a FROM mytmp)
AND b IN (SELECT b FROM mytmp)
ВНУТРЕННЕЕ СОЕДИНЕНИЕ (технически это можно сделать безопасным, но часто это не делается)
Причина, по которой я не рекомендую использовать внутреннее объединение в качестве фильтра, заключается в том, что на практике люди часто допускают дубликаты в правой таблице, которые вызывают дубликаты в левой таблице. И что еще хуже, они иногда делают конечный результат отличным, в то время как левая таблица может фактически не быть уникальной (или не уникальной в выбранных вами столбцах). Кроме того, это дает вам возможность фактически выбрать столбец, который не существует в левой таблице.
SELECT T1.* FROM T1
INNER JOIN
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b
Самые распространенные ошибки:
- Присоединение непосредственно к T2, без безопасного подзапроса. В результате чего возникает риск дублирования)
- SELECT * (гарантированно получить столбцы из T2)
- SELECT c (не гарантирует, что ваш столбец будет приходить и всегда будет поступать из T1)
- Нет DISTINCT или DISTINCT в неправильном месте
КОНКАТЕНЦИЯ КОЛОНН С СЕПАРАТОРОМ (не очень безопасно, ужасная производительность)
Функциональная проблема заключается в том, что если вы используете разделитель, который может находиться в столбце, будет сложно убедиться, что результат будет на 100% точным. Техническая проблема заключается в том, что этот метод часто выполняет преобразования типов и полностью игнорирует индексы, что может привести к ужасной производительности. Несмотря на эти проблемы, я должен признать, что иногда я все еще использую его для специальных запросов в небольших наборах данных.
SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN
(SELECT CONCAT(a,"_",b) FROM T2)
Обратите внимание, что если ваши столбцы являются числовыми, некоторые диалекты SQL потребуют от вас сначала привести их к строкам. Я верю, что SQL-сервер сделает это автоматически.
Подводя итог: как обычно, в SQL есть много способов сделать это, использование безопасных вариантов позволит избежать неожиданностей и сэкономит ваше время и трудности в долгосрочной перспективе.