Consulta SQL para encontrar un registro con ID que no está en otra tabla

123

Tengo dos tablas con clave primaria vinculante en la base de datos y deseo encontrar un conjunto disjunto entre ellas. Por ejemplo,

  • Table1tiene columnas ( ID, Name) y datos de muestra:(1 ,John), (2, Peter), (3, Mary)
  • Table2tiene columnas ( ID, Address) y datos de muestra:(1, address2), (2, address2)

Entonces, ¿cómo creo una consulta SQL para poder obtener la fila con el ID table1que no está en table2. En este caso, (3, Mary)¿debe devolverse?

PD. El ID es la clave principal para esas dos tablas.

Gracias por adelantado.

johnklee
fuente
3
Como consejo para futuras preguntas: defina siempre qué sistema de base de datos (y qué versión de esa base de datos) está utilizando. SQL es solo el lenguaje de consulta estructurado utilizado por la mayoría de los sistemas de bases de datos, lo que realmente no ayuda mucho ... a menudo, las bases de datos tienen extensiones y características mucho más allá del estándar ANSI / ISO SQL que facilitan la resolución del problema, pero para eso, usted necesita decirnos qué base de datos está utilizando
marc_s
5
@marc_s: ¿Qué pasa si están buscando una solución independiente del idioma, porque necesitan admitir múltiples sistemas de bases de datos subyacentes, o la implementación de la base de datos se abstrae?
dwanderson
Hola @marc_s, estoy usando PostgreSQL en este caso. Gracias por recordárselo.
johnklee

Respuestas:

213

Prueba esto

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)
Príncipe Jea
fuente
8
@PrinceJea en realidad depende. Vea aquí para una aclaración
John Woo
Cuando tengo 20 datos, funciona, pero cuando tengo 20000 datos, no funciona, estoy confundido ahora.
Frank
1
No tengo idea de por qué, pero no funciona. Tengo alrededor de 10000 filas en la tabla. En mi caso, la solución de @JohnWoo funcionó bien.
Munam Yousuf
4
No funcionará si tenemos demasiados valores en "Not In" ya que este método tiene un número limitado de valores cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato
2
Tuve que hacerlo así: seleccione i de la Tabla1 DONDE NO ESTÉ EN (SELECCIONE i DE la Tabla2 donde no es nulo ) y no es nulo
jaksco
93

Utilizar LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL
John Woo
fuente
Creo que este es el enfoque más rápido para una base de datos muy grande
Alex Jolig
12

Hay básicamente 3: enfoques para que not exists, not iny left join / is null.

LEFT JOIN con IS NULL

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

NO EN

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

NO EXISTE

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

¿Cuál es mejor? La respuesta a esta pregunta podría ser mejor dividirla en los principales proveedores de RDBMS específicos. En términos generales, se debe evitar el uso select ... where ... in (select...)cuando se desconoce la magnitud del número de registros en la subconsulta. Algunos proveedores pueden limitar el tamaño. Oracle, por ejemplo, tiene un límite de 1000 . Lo mejor que puede hacer es probar los tres y mostrar el plan de ejecución.

Específicamente de PostgreSQL, plan de ejecución de NOT EXISTSy LEFT JOIN / IS NULLson lo mismo. Personalmente prefiero la NOT EXISTSopción porque muestra mejor la intención. Después de toda la semántica es que usted quiere encontrar registros en A que sus pk no existen en B .

Sin embargo, antiguo pero aún dorado, específico de PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

L. Holanda
fuente
10

Alternativa rápida

Ejecuté algunas pruebas (en postgres 9.5) usando dos tablas con ~ 2M filas cada una. Esta consulta a continuación funcionó al menos 5 * mejor que las otras consultas propuestas:

-- 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;
polvoazul
fuente
1
Esto no fue más rápido que la solución de @Jhon Woo. Estoy usando Postgres 9.6 y con la solución de Jhon, el tiempo de ejecución es de aproximadamente 60 ms. Mientras que califiqué esta solución después de 120 segundos y sin resultado.
froy001
5

Teniendo en cuenta los puntos señalados en el comentario / enlace de @John Woo anterior, así es como lo manejaría normalmente:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)
CaseyR
fuente
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
JoshYates1980
fuente