MySQL Join Wo nicht vorhanden

79

Ich habe eine MySQL-Abfrage, die zwei Tabellen verbindet

  • Wähler
  • Haushalte

Sie schließen sich an voters.household_idund household.id.

Nun , was ich tun müssen , ist , es zu ändern , wo die Wähler Tabelle in eine dritte Tabelle namens Beseitigung verbunden ist, zusammen voter.idund elimination.voter_id. Der Haken ist jedoch, dass ich alle Datensätze in der Wählertabelle ausschließen möchte, die einen entsprechenden Datensatz in der Eliminierungstabelle haben.

Wie erstelle ich eine Abfrage, um dies zu tun?

Dies ist meine aktuelle Anfrage:

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
quelle

Antworten:

190

Ich würde wahrscheinlich ein verwenden LEFT JOIN, das Zeilen zurückgibt, auch wenn es keine Übereinstimmung gibt, und dann können Sie nur die Zeilen ohne Übereinstimmung auswählen, indem Sie nach NULLs suchen .

Also so etwas wie:

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

Ob dies mehr oder weniger effizient ist als die Verwendung einer Unterabfrage, hängt von der Optimierung, den Indizes, der Möglichkeit ab, mehr als eine Eliminierung pro Wähler usw. zu erzielen.

NickZoic
quelle
3
+1 viel schneller bei hoher Last als bei Unterabfragen + Wenn U JOINs anstelle von Unterabfragen ausführen kann - machen Sie einfach JOINs, sie sind für den Analizer viel einfacher. Ein weiteres nützliches Beispiel: U möchte möglicherweise ein Ergebnis erhalten, wenn sich in einer rechten Tabelle einige Zeilen befinden oder wenn es keine gibt: Beispiel SELECT V.* FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id OR E.voter_id IS NULL: Wenn Sie nicht alle Datensätze für jede Zeile von links in der rechten Tabelle speichern möchten.
Arthur Kushman
1
Wie würden Sie diese Abfrage ändern, um Zeilen zu finden, in denen nicht vorhanden ist E, wann E.voter_idsie sich NULLin dem Datensatz befinden können, aus dem wir stammen JOIN?
Danny Beckett
Sie müssen die Tabellen mit einer gemeinsamen Spalte oder einem verwandten Wert verknüpfen. Aber ich denke, das könnte funktionieren (ungetestet):SELECT V.*, COUNT(E.*) AS `countE` FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id WHERE countE = 0;
ericek111
7

Ich würde ein "wo nicht existiert" verwenden - genau wie Sie es in Ihrem Titel vorschlagen:

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

Dies ist möglicherweise geringfügig schneller als ein Link-Join (natürlich abhängig von Ihren Indizes, der Kardinalität Ihrer Tabellen usw.) und mit ziemlicher Sicherheit viel schneller als die Verwendung von IN.

Ian Clelland
quelle
Danke dafür - war definitiv schneller für mich.
Spidie
5

Dafür gibt es drei Möglichkeiten.

  1. Möglichkeit

    SELECT  lt.* FROM    table_left lt
    LEFT JOIN
        table_right rt
    ON      rt.value = lt.value
    WHERE   rt.value IS NULL
    
  2. Möglichkeit

    SELECT  lt.* FROM    table_left lt
    WHERE   lt.value NOT IN
    (
    SELECT  value
    FROM    table_right rt
    )
    
  3. Möglichkeit

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