2009-04-15 9 views
46

Ich habe eine MySQL-Abfrage, die zwei TabellenMySQL Join Wo Not Exists

  • Wähler
  • Haushalte sie kommen auf voters.household_id und household.id

    Nun, was ich tun verbindet müssen ist es zu ändern, wo die Wähler Tabelle mit einer dritten Tabelle namens Beseitigung verbunden ist, entlang Voter.ID und Elimination.Voter_ID, wie auch immer der Fang ist, dass ich alle Datensätze in der Wähler-Tabelle, die eine entsprechende Aufzeichnung in der Beseitigung haben, auszuschließen Tabelle. Wie erstelle ich eine Abfrage, um dies zu tun?

das ist meine aktuelle Abfrage

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 

Antwort

122

ich wahrscheinlich ein LEFT JOIN verwenden würde, die Reihen selbst zurück, wenn es keine Übereinstimmung gibt, und dann können Sie nur die Zeilen ohne Spiel auswählen, indem Sie Überprüfen auf NULL.

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 das mehr oder weniger effizient als eine Unterabfrage ist abhängig von Optimierung, Indizes, ob ihre möglich mehr als eine Eliminierung pro Wähler usw.

+8

+1 zurück schneller als Unterabfragen – ravi404

+1

+1 viel schneller auf Hochlast dann Unterabfragen + wenn U JOINs anstelle von Unterabfragen tun können - nur JOINs sie sind viel einfacher für analizer. Ein anderes nützliches Beispiel, U könnte das Ergebnis erhalten, wenn es einige Zeilen in einer rechten Tabelle gibt oder wenn es keine gibt: 'SELECT V. * VON voter V LEFT JOIN eliminierung E ON V.id = E.voter_id ODER E .voter_id IS NULL' Beispiel: wenn U nicht alle Datensätze in der rechten Tabelle für jede Zeile von links speichern soll. –

4

ich würde verwenden eine ‚wo nicht existiert‘ - genau so, wie Sie 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 

, die schneller sein marginal kann als eine linke tut kommen (natürlich je nach Ihre Indizes, Kardinalität Ihrer Tabellen, usw.), und ist fast sicher viel schneller als mit IN.

+0

Danke dafür - war definitiv schneller für mich. – spidie

15
+2

Fazit dieses Artikels: "Deshalb ist die beste Möglichkeit, nach fehlenden Werten in MySQL zu suchen, die Verwendung von LEFT JOIN/IS NULL oder NOT IN statt NOT EXISTS." – marcovtwout

+3

Link nur Antwort = schlecht – Andrew

+0

Nicht verwandt, aber ein Framework Zu meiner Überraschung (Laravel) generiert NOT EXIST-Abfrage, wenn whereDoesntHave Abfragen – Tebe

1

Es gibt drei Möglichkeiten, das zu tun.

  1. Option
 
     SELECT lt.* FROM table_left l 
     LEFT JOIN 
      table_right r 
     ON  rt.value = lt.value 
     WHERE rt.value IS NULL 
  1. Option
 
     SELECT lt.* FROM table_left l 
     WHERE lt.value NOT IN 
     (
     SELECT value 
     FROM table_right r 
     ) 
  1. Option
 
     SELECT lt.* FROM table_left l 
     WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM table_right r 
     WHERE rt.value = lt.value 
     )