AVISO SOBRE SOLUÇÕES:
MUITAS SOLUÇÕES EXISTENTES DARÃO SAÍDA ERRADA SE AS LINHAS NÃO SÃO ÚNICAS
Se você é a única pessoa que cria tabelas, isso pode não ser relevante, mas várias soluções fornecerão um número diferente de linhas de saída do código em questão, quando uma das tabelas não puder conter linhas exclusivas.
AVISO SOBRE DECLARAÇÃO DE PROBLEMA:
EM VÁRIAS COLUNAS NÃO EXISTE, PENSE CUIDADOSAMENTE O QUE VOCÊ QUER
Quando vejo uma entrada com duas colunas, consigo imaginar duas coisas:
- O valor da coluna ae coluna b aparecem na outra tabela independentemente
- Os valores das colunas ae coluna aparecem na outra tabela juntos na mesma linha
O cenário 1 é bastante trivial, basta usar duas instruções IN.
De acordo com a maioria das respostas existentes, forneço aqui uma visão geral das abordagens mencionadas e adicionais para o Cenário 2 (e um breve julgamento):
EXISTS (Seguro, recomendado para SQL Server)
Conforme fornecido por @mrdenny, EXISTS soa exatamente como o que você está procurando, eis o exemplo dele:
SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2
WHERE T1.a=T2.a and T1.b=T2.b)
ESQUERDA SEMI JOIN (Seguro, recomendado para dialetos que o suportam)
Essa é uma maneira muito concisa de ingressar, mas infelizmente a maioria dos dialetos SQL, incluindo o SQL Server, atualmente não o suporta.
SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b
Várias instruções IN (seguras, mas cuidado com a duplicação de código)
Como mencionado pelo @cataclysm, usar duas instruções IN também pode ajudar, talvez até supere as outras soluções. No entanto, você deve ter muito cuidado com a duplicação de código. Se você desejar selecionar uma tabela diferente ou alterar a instrução where, é um risco aumentado que você crie inconsistências em sua lógica.
Solução básica
SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)
Solução sem duplicação de código (acredito que isso não funcione em consultas regulares do 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)
INNER JOIN (tecnicamente, isso pode ser feito com segurança, mas muitas vezes isso não é feito)
A razão pela qual eu não recomendo o uso de uma junção interna como filtro, é porque, na prática, as pessoas geralmente deixam duplicatas na tabela correta, causando duplicatas na tabela esquerda. E, para piorar a situação, às vezes eles diferenciam o resultado final, enquanto a tabela esquerda pode não precisar ser exclusiva (ou não exclusiva nas colunas que você selecionar). Além disso, oferece a chance de realmente selecionar uma coluna que não existe na tabela esquerda.
SELECT T1.* FROM T1
INNER JOIN
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b
Erros mais comuns:
- Juntando-se diretamente no T2, sem uma subconsulta segura. Resultando em risco de duplicação)
- SELECT * (garantido para obter colunas de T2)
- SELECT c (não garante que sua coluna venha e sempre venha de T1)
- Não DISTINCT ou DISTINCT no lugar errado
CONCATENAÇÃO DE COLUNAS COM SEPARADOR (Desempenho não muito seguro, horrível)
O problema funcional é que, se você usar um separador que pode ocorrer em uma coluna, fica complicado garantir que o resultado seja 100% exato. O problema técnico é que esse método geralmente gera conversões de tipo e ignora completamente os índices, resultando em um desempenho possivelmente horrível. Apesar desses problemas, tenho que admitir que às vezes ainda o uso para consultas ad-hoc em pequenos conjuntos de dados.
SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN
(SELECT CONCAT(a,"_",b) FROM T2)
Observe que, se suas colunas forem numéricas, alguns dialetos SQL exigirão que você as converta em cadeias primeiro. Acredito que o SQL Server fará isso automaticamente.
Para finalizar: Como de costume, existem muitas maneiras de fazer isso no SQL, usar opções seguras evitará surpresas e economizará tempo e dinheiro a longo prazo.