MySQL Приєднуйтесь, де немає


80

У мене є запит MySQL, який об’єднує дві таблиці

  • Виборці
  • Домогосподарства

Вони приєднуються до voters.household_idі household.id.

Тепер то , що мені потрібно зробити, щоб змінити його , де таблиця виборців приєднується до третьої таблиці під назвою ліквідації, а також voter.idі elimination.voter_id. Однак фішка полягає в тому, що я хочу виключити будь-які записи в таблиці виборців, які мають відповідний запис у таблиці вилучень.

Як створити запит для цього?

Це мій поточний запит:

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 

Відповіді:


191

Я б, напевно, використовував a LEFT JOIN, який повертає рядки, навіть якщо збігу немає, і тоді ви можете вибрати лише ті рядки, які не збігаються, перевіривши наявність NULLs.

Отже, щось на зразок:

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

Чи буде це більш-менш ефективним, ніж використання підзапиту, залежить від оптимізації, індексів, чи можливо мати більше одного виключення на виборця тощо.


3
+1 набагато швидше на високонавантажених, ніж підзапитах + якщо U може робити JOINs замість підзапитів - просто JOINs вони набагато простіші для аналізатора. Ще один корисний приклад: U може захотіти отримати результат, якщо в правій таблиці є кілька рядків або якщо їх немає: SELECT V.* FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id OR E.voter_id IS NULLнаприклад: якщо U не хоче зберігати всі записи в правій таблиці для кожного рядка зліва.
Артур Кушман,

1
Як би ви змінили цей запит, щоб знайти рядки, яких не існує E, коли вони E.voter_idможуть бути NULLу наборі даних, з якого ми створюємо JOIN?
Денні Беккет,

Вам потрібно зв’язати таблиці разом із загальним стовпцем або пов’язаним значенням. Але я думаю, що це могло б спрацювати (не перевірено):SELECT V.*, COUNT(E.*) AS `countE` FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id WHERE countE = 0;
ericek111

7

Я б використав "де не існує" - саме так, як ви пропонуєте у своєму заголовку:

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

Це може бути незначно швидше, ніж виконувати ліве приєднання (звичайно, залежно від ваших індексів, потужності ваших таблиць тощо), і майже напевно набагато швидше, ніж використання IN.


Дякую за це - для мене, безумовно, було швидше.
spidie

6

Є три можливі способи зробити це.

  1. Варіант

    SELECT  lt.* FROM    table_left lt
    LEFT JOIN
        table_right rt
    ON      rt.value = lt.value
    WHERE   rt.value IS NULL
    
  2. Варіант

    SELECT  lt.* FROM    table_left lt
    WHERE   lt.value NOT IN
    (
    SELECT  value
    FROM    table_right rt
    )
    
  3. Варіант

    SELECT  lt.* FROM    table_left lt
    WHERE   NOT EXISTS
    (
    SELECT  NULL
    FROM    table_right rt
    WHERE   rt.value = lt.value
    )
    
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.