Únete a MySQL donde no existe

80

Tengo una consulta MySQL que une dos tablas

  • Votantes
  • Hogares

Se unen a voters.household_idy household.id.

Ahora lo que tengo que hacer es modificarlo donde la mesa de votantes se une a una tercera mesa llamada eliminación, junto con voter.idy elimination.voter_id. Sin embargo, el problema es que quiero excluir cualquier registro en la tabla de votantes que tenga un registro correspondiente en la tabla de eliminación.

¿Cómo creo una consulta para hacer esto?

Esta es mi consulta actual:

SELECT `voter`.`ID`, `voter`.`Last_Name`, `voter`.`First_Name`,
       `voter`.`Middle_Name`, `voter`.`Age`, `voter`.`Sex`,
       `voter`.`Party`, `voter`.`Demo`, `voter`.`PV`,
       `household`.`Address`, `household`.`City`, `household`.`Zip`
FROM (`voter`)
JOIN `household` ON `voter`.`House_ID`=`household`.`id`
WHERE `CT` = '5'
AND `Precnum` = 'CTY3'
AND  `Last_Name`  LIKE '%Cumbee%'
AND  `First_Name`  LIKE '%John%'
ORDER BY `Last_Name` ASC
LIMIT 30 
gsueagle2008
fuente

Respuestas:

191

Probablemente usaría a LEFT JOIN, que devolverá filas incluso si no hay coincidencia, y luego puede seleccionar solo las filas sin coincidencia al verificar NULLs.

Entonces, algo como:

SELECT V.*
FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id
WHERE E.voter_id IS NULL

Si eso es más o menos eficiente que usar una subconsulta depende de la optimización, los índices, si es posible tener más de una eliminación por votante, etc.

NickZoic
fuente
3
+1 mucho más rápido en carga alta que en subconsultas + si U puede hacer JOINs en lugar de subconsultas, simplemente haga JOINs, son mucho más simples para el analizador. Otro ejemplo útil, U puede querer obtener un resultado si hay algunas filas en una tabla de la derecha o si no hay nadie: SELECT V.* FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id OR E.voter_id IS NULLej .: si U no desea almacenar todos los registros en la tabla de la derecha para cada fila de la izquierda.
Arthur Kushman
1
¿Cómo modificaría esta consulta para encontrar filas que no existen en E, cuándo E.voter_idpuede estar NULLen el conjunto de datos del que venimos JOIN?
Danny Beckett
Debe vincular las tablas con alguna columna común o valor relacionado. Pero creo que esto podría funcionar (no probado):SELECT V.*, COUNT(E.*) AS `countE` FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id WHERE countE = 0;
ericek111
7

Usaría un 'donde no existe', exactamente como sugieres en tu título:

SELECT `voter`.`ID`, `voter`.`Last_Name`, `voter`.`First_Name`,
       `voter`.`Middle_Name`, `voter`.`Age`, `voter`.`Sex`,
       `voter`.`Party`, `voter`.`Demo`, `voter`.`PV`,
       `household`.`Address`, `household`.`City`, `household`.`Zip`
FROM (`voter`)
JOIN `household` ON `voter`.`House_ID`=`household`.`id`
WHERE `CT` = '5'
AND `Precnum` = 'CTY3'
AND  `Last_Name`  LIKE '%Cumbee%'
AND  `First_Name`  LIKE '%John%'

AND NOT EXISTS (
  SELECT * FROM `elimination`
   WHERE `elimination`.`voter_id` = `voter`.`ID`
)

ORDER BY `Last_Name` ASC
LIMIT 30

Eso puede ser un poco más rápido que hacer una combinación izquierda (por supuesto, dependiendo de sus índices, cardinalidad de sus tablas, etc.), y es casi seguro que es mucho más rápido que usar IN.

Ian Clelland
fuente
Gracias por eso, definitivamente fue más rápido para mí.
spidie
6

Hay tres formas posibles de hacerlo.

  1. Opción

    SELECT  lt.* FROM    table_left lt
    LEFT JOIN
        table_right rt
    ON      rt.value = lt.value
    WHERE   rt.value IS NULL
    
  2. Opción

    SELECT  lt.* FROM    table_left lt
    WHERE   lt.value NOT IN
    (
    SELECT  value
    FROM    table_right rt
    )
    
  3. Opción

    SELECT  lt.* FROM    table_left lt
    WHERE   NOT EXISTS
    (
    SELECT  NULL
    FROM    table_right rt
    WHERE   rt.value = lt.value
    )
    
Dumindu Madushanka
fuente