SQL-запит для пошуку запису з ідентифікатором не в іншій таблиці


123

У мене є дві таблиці із прив'язкою первинного ключа в базі даних, і я хочу знайти між ними розрізнений набір. Наприклад,

  • Table1містить стовпці ( ID, Name) та вибіркові дані:(1 ,John), (2, Peter), (3, Mary)
  • Table2містить стовпці ( ID, Address) та вибіркові дані:(1, address2), (2, address2)

Тож як я можу створити SQL-запит, щоб я міг отримати рядок з ідентифікатором, з table1якого немає table2. У такому випадку (3, Mary)слід повернути?

Пс. Ідентифікатор - це первинний ключ для цих двох таблиць.

Заздалегідь спасибі.


3
Як підказка щодо майбутніх питань: завжди визначайте, яку систему бази даних (і яку версію цієї бази даних) ви використовуєте. SQL - це лише структурована мова запитів, яка використовується більшості систем баз даних - це не дуже допомагає ... часто, бази даних мають розширення та можливості, що виходять за рамки стандарту ANSI / ISO SQL, що дозволяє вирішити проблему просто - але для цього ви нам потрібно сказати, яку базу даних ви використовуєте
marc_s

5
@marc_s: Що робити, якщо вони шукають мовно-агностичне рішення, оскільки їм потрібно підтримувати декілька базових систем баз даних, або реалізація бази даних буде відмовлена?
dwanderson

Привіт @marc_s, я використовую PostgreSQL в цьому випадку. Дякую за нагадування.
johnklee

Відповіді:


213

Спробуйте це

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea насправді це залежить. Дивіться тут для уточнення
Джон Ву

Коли у мене є 20 даних, це працює, але коли у мене є 20000 даних, це не працює, я зараз плутаю.
Френк

1
Немає ідеї чому, але це не працює. У мене в таблиці близько 10000 рядків. У моєму випадку рішення @JohnWoo працювало чудово.
Мунам Юсуф

4
Це не спрацює, ми занадто багато значень у "Не в", оскільки цей метод має обмежену кількість значень cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
Я повинен був зробити це так: виберіть i з таблиці 1, де я НЕ (виберіть i з таблиці 2, де я не є нульовим ), і я не є нульовим
jaksco

93

Використовуйте LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

Я думаю, що це швидший підхід для дуже великої бази даних
Алекс Джоліг

12

Є в основному 3 підходи до того , що: not exists, not inі left join / is null.

ЛІВО ПРИЄДНАЙТЕСЬ З НУЛЮ

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

НЕ В

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

НЕ Є

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

Який з них кращий? Відповідь на це питання, можливо, буде краще розбити на основних конкретних постачальників RDBMS. Взагалі кажучи, слід уникати використання, select ... where ... in (select...)коли величина кількості записів у підзапиті невідома. Деякі постачальники можуть обмежити розмір. Наприклад, Oracle має ліміт 1000 . Найкраще зробити це спробувати всі три та показати план виконання.

Конкретно формуйте PostgreSQL, план виконання NOT EXISTSі LEFT JOIN / IS NULLтакі самі. Я особисто віддаю перевагу NOT EXISTSваріанту, оскільки він краще показує наміри. В кінці кінців семантичний, що ви хочете , щоб знайти записи в тому , що його рк не існує в B .

Старе, але все-таки золото, характерне для PostgreSQL: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

Швидка альтернатива

Я провів декілька тестів (на постгресах 9.5), використовуючи дві таблиці з ~ 2М рядків у кожній. Цей запит нижче виконується щонайменше на 5 * краще, ніж інші запропоновані запити:

-- 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;

1
Це було не швидше, ніж рішення @Jhon Woo. Я використовую Postgres 9.6 і час виконання рішення Джона становить близько 60 мс. Поки я цілком це рішення після 120 сек і жодного результату.
froy001

5

Маючи на увазі моменти, викладені в коментарі / посиланні @John Woo вище, я, як правило, вирішував би це:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.