Consulta SQL para localizar o registro com o ID que não está em outra tabela


123

Eu tenho duas tabelas com chave primária de ligação no banco de dados e desejo encontrar um conjunto separado entre elas. Por exemplo,

  • Table1possui colunas ( ID, Name) e dados de amostra:(1 ,John), (2, Peter), (3, Mary)
  • Table2possui colunas ( ID, Address) e dados de amostra:(1, address2), (2, address2)

Então, como eu crio uma consulta SQL para que eu possa buscar a linha com o ID daquele table1que não está table2. Nesse caso, (3, Mary)deve ser retornado?

Ps. O ID é a chave primária para essas duas tabelas.

Desde já, obrigado.


3
Como uma dica para perguntas futuras: sempre defina qual sistema de banco de dados (e qual versão desse banco de dados) você está usando. SQL é apenas a Linguagem de Consulta Estruturada usada pela maioria dos sistemas de banco de dados - o que não ajuda muito ... muitas vezes, os bancos de dados têm extensões e recursos muito além do ANSI / ISO SQL Standard que facilitam a solução do problema - mas, para isso, você necessidade de nos dizer o banco de dados que você está usando
marc_s

5
@marc_s: E se eles estiverem procurando uma solução independente de idioma, porque precisam oferecer suporte a vários sistemas de banco de dados subjacentes ou se a implementação do banco de dados for abstraída?
precisa saber é o seguinte

Oi @marc_s, estou usando o PostgreSQL neste caso. Obrigado pela lembrança.
johnklee

Respostas:


213

Tente isto

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea realmente depende. Veja aqui para esclarecimentos
John Woo

Quando tenho 20 dados, ele funciona, mas quando tenho 20000 dados, não funciona, estou confuso agora.
Frank

1
Não faço ideia do porquê, mas não está funcionando. Eu tenho cerca de 10000 linhas na tabela. No meu caso, a solução da @JohnWoo funcionou bem.
Munam Yousuf

4
É não funcionará nos muitos valores em "Not In" uma vez que este método tem um número limitado de valores FC: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
Eu tinha que fazê-lo como este: escolha i da tabela 1 onde eu não IN (SELECT i DE Table2 onde eu não for nulo ) e eu não é nulo
jaksco

93

Usar LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

Eu acho que esta é a abordagem mais rápida para um banco de dados muito grande
Alex Jolig

12

Existem basicamente 3 abordagens para que: not exists, not ine left join / is null.

JUNTA ESQUERDA com IS NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

NÃO EM

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

NÃO EXISTE

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

Qual é o melhor? A resposta a esta pergunta pode ser melhor dividida em grandes fornecedores específicos de RDBMS. De um modo geral, deve-se evitar o uso select ... where ... in (select...)quando a magnitude do número de registros na subconsulta for desconhecida. Alguns fornecedores podem limitar o tamanho. O Oracle, por exemplo, tem um limite de 1.000 . A melhor coisa a fazer é tentar os três e mostrar o plano de execução.

Especificamente, forma o PostgreSQL, plano de execução NOT EXISTSe LEFT JOIN / IS NULLé o mesmo. Pessoalmente, prefiro a NOT EXISTSopção porque mostra melhor a intenção. Depois de toda a semântica é que você quiser encontrar registros em um que seus pk não existem em B .

Porém, antigo mas ainda ouro, específico para o PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Alternativa rápida

Fiz alguns testes (no postgres 9.5) usando duas tabelas com ~ 2 milhões de linhas cada. Esta consulta abaixo teve um desempenho pelo menos 5 * melhor do que as outras consultas propostas:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;

1
Isso não foi mais rápido que a solução de @Jhon Woo. Estou usando o Postgres 9.6 e com o tempo de execução da solução de Jhon é de cerca de 60ms. Enquanto eu bastante esta solução após 120 seg e sem resultado.
precisa saber é o seguinte

5

Tendo em mente os pontos mencionados no comentário / link de John Woo acima, é assim que eu normalmente lidaria com isso:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.