Напротив внутреннего соединения

Что будет противоположностью внутреннего соединения? Для таблицы Table Person (int PersonId, varchar PersoName, int AddrId), я хочу знать строки в Person с плохим AddrId, которые не имеют строки в таблице Address.

Ответы

Ответ 1

Что будет противоположностью внутреннего соединения?

Соединение OUTER, которое может быть трех вариантов:

  • ЛЕВАЯ
  • RIGHT
  • ПОЛНОЕ

Это хорошее визуальное представление JOINs

Я хочу знать строки в Person with bad AddrId, которые не имеют строки в таблице Address.

Использование LEFT JOIN/IS NULL

   SELECT p.*
     FROM PERSON p
LEFT JOIN ADDRESS a ON a.addrid = p.addrid
    WHERE a.addrid IS NULL

Использование NOT EXISTS

SELECT p.*
  FROM PERSON p
 WHERE NOT EXISTS(SELECT NULL
                    FROM ADDRESS a
                   WHERE a.addrid = p.addrid)

Использование NOT IN

SELECT p.*
  FROM PERSON p
 WHERE p.addrid NOT IN (SELECT a.addrid
                          FROM ADDRESS a)

Ответ 2

Внутреннее соединение не является диаметрическим для Outer Join. Они служат различным целям. Однако общий шаблон для поиска строк из одной таблицы, которых нет в другом, заключается в использовании Outer Join:

Select ...
From Table1
    Left Join Table2
        On Table2.ForeignKeyCol = Table1.PrimaryKeyCol
Where Table2.PrimaryKeyCol Is Null

Это возвращает все строки из Таблицы 1 и любые соответствующие строки из Таблицы 2, так что если в заданной таблице Table1 нет соответствия Table2, возвращается нуль для столбцов Table2. К тому времени, требуя, чтобы столбец с непустым значением (Table2.PrimaryKeyCol) был Null, я получу все строки из таблицы 1, которых нет в таблице2. Используя ваши имена таблиц в таблице, у нас будет что-то вроде:

Select ...
From Person
    Left Join Address
        On Address.PersonId = Person.Id
Where Address.Id Is Null

Ответ 3

Если вы считаете внутреннее соединение как строки из двух таблиц, удовлетворяющих определенному условию, то противоположными будут строки в любой таблице, которые этого не делают.

Например, следующее будет выбирать всех людей с адресами в таблице адресов:

SELECT p.PersonName, a.Address
FROM people p
JOIN addresses a
    ON p.addressId = a.addressId

Я полагаю, что "противоположностью" этого было бы выбор всех людей без адресов и всех адресов без людей. Однако, похоже, это не то, о чем вы просите, вам кажется, что вас интересует только один компонент этого: все люди без адреса в таблице адресов.

Для этого лучше было бы левое соединение:

SELECT p.PersonName
FROM people p
LEFT JOIN addresses a
   ON p.addressId = a.addressId
WHERE a.addressId IS NULL

Обратите внимание, что часто некоторые предпочитают писать по-другому, поскольку, по их мнению, это более читаемо (однако, по моему опыту, с большими таблицами он работает хуже, чем выше):

SELECT PersonName
FROM people
WHERE addressId NOT IN (SELECT addressId FROM addresses)

Ответ 4

Я думаю, что лучшим решением будет использование EXISTS. Вот так:

SELECT * FROM Person P WHERE P.AddrId NOT NULL И НЕ СУЩЕСТВУЕТ (SELECT 1 FROM Address A WHERE A.AddrId = P.AddrId)

В приведенном выше запросе будет указан каждый человек, который установлен в AddrId, но не имеет соответствующей записи в таблице Address.

Обь.: Используйте константу 1 в запросе EXISTS, чтобы избежать доступа к таблице.