В чем разница между ВНУТРЕННИМ И ВНЕШНИМ СОЕДИНЕНИЕМ?


35

Я новичок в SQL и хотел знать, в чем разница между этими двумя JOINтипами?

SELECT * 
FROM user u
INNER JOIN telephone t ON t.user_id = u.id

SELECT * 
FROM user u
LEFT OUTER JOIN telephone t ON t.user_id = u.id

Когда я должен использовать один или другой?


6
это подходит как вопрос DBA? Это кажется мне более сложным вопросом.
BlackICE

1
@ Поделитесь своими мыслями о Мете
Сатьяджит Бхат,

@ Давид, тогда VtC, если вы считаете, что это неправильно для сайта. Мы всегда можем открыть заново.
Jcolebrand

3
Я думаю, что это отличный вопрос, и очень подходящий для сайта.
Датагод

это нужно убрать из DBA, если только не новичок в DBA, настроенный для точной настройки производительности DB: P
AmDB

Ответы:


32
  • Внутреннее соединение будет выбирать только запись , где соединяемые ключи находятся в обеих указанных таблицах.
  • Левые внешнее соединение будет выбрать все записи из первой таблицы, а также любые записи во второй таблице , которые соответствуют присоединившимся ключам.
  • Правая внешнее соединение будет выбрать все записи из второй таблицы, и любые записи в первой таблице , которые соответствуют присоединившимся ключам.

В первом примере вы вернете список пользователей и телефонных номеров, только если для пользователя существует хотя бы одна телефонная запись.

Во втором примере вы вернете список всех пользователей, а также любые телефонные записи, если они доступны (если они недоступны, вы получите NULLза телефонные значения).


13

Каждый раз, когда кто-то задает этот вопрос, есть ответ: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Надеюсь, это поможет вам понять,


3
Я работал с объединениями в течение 20 лет, и эти диаграммы мне показались странными.
Хоган

3
Я с @Hogan - диаграммы не являются лучшим объяснением этого ... сетка, показывающая, какие комбинации будут возвращены, вероятно, будет лучше.
Джо

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

@jamesryan это не так, они не связаны идеально, объединения похожи на декартово произведение множеств, а не на пересечение и объединение, аналог диаграммы Венна работает, только если вы соединяетесь по уникальным ключам, если у вас есть дублированные ключи, то вы теряете картезианский аспект продукта.
Будет

1
Я категорически не согласен, диаграммы Венна уже имеют очень четкую интерпретацию, пересечение множеств и объединение. Объединения не подходят под эту интерпретацию, когда вы объединяете неуникальные ключи. Я думаю, вы слишком широко интерпретируете диаграммы Венна.
Будет

8

Внутреннее соединение возвращает строки , которые могут быть объединены на основе присоединиться к критериям. Внешнее соединение возвращает эти и все строки ...    ... из первой таблицы для соединения слева    ... из второй таблицы для соединения справа    ... из обоего таблиц для полного соединения




Выбор того, когда использовать один или другой, зависит от того, какие данные вам нужны. Для вашего примера, если вам нужны только записи, которые имеют user_ids с телефона и совпадают с идентификаторами в user, используйте внутреннее соединение. Если вы также хотите включить строки от пользователя, у которых нет соответствующей телефонной записи, то будет уместным левое соединение.

Для получения дополнительной информации см. Этот вопрос на StackOverflow .


7

Если у вас есть 2 таблицы, как показано ниже:

Table1 :   A1    B1          Table2  :    B2     C2 
           -     -                        -      -
           1     2                        1      1
           2     4                        2      4
           3     5                        5      2

Если вы используете Inner Join, вы получаете:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2

Если вы используете Full Outer Join, вы получаете:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2
 2      4    NULL     NULL
NULL   NULL    1       1

Если вы используете Left Outer Join, вы получаете:

 A1     B1     B2      C2  
 -      -      -       -
 1      2      2       4
 3      5      5       2
 2      4    NULL     NULL

6

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

SELECT SNO , PNO 
FROM   SP 
UNION  
SELECT SNO , 'nil' AS PNO 
FROM   S 
WHERE  SNO NOT IN ( SELECT SNO FROM SP )

В качестве альтернативы тот же результат может быть получен с помощью оператора внешнего соединения SQL в сочетании с COALESCE, как здесь:

SELECT SNO , COALESCE ( PNO , 'nil' ) AS PNO 
FROM ( S NATURAL LEFT OUTER JOIN SP ) AS TEMP

Замечание о внешнем соединении (4.6) в статье «Теория SQL и реляционная теория: как писать точный код SQL», автор CJ Date


5

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

Допустим, таблица table1 имеет следующие пары первичного ключа и данных: (1, a), (2, b), (3, c)

Давайте также скажем, что таблица2 имеет следующие пары первичного ключа и данных: (1, веселье), (3, может), (4, случиться)

Таким образом, внутреннее соединение table1 к table2 на первичных ключах приведет к следующим результирующим триплетам (с общим первичным ключом первым, вторым элементом первой таблицы и вторым элементом второй таблицы): (1, a, fun), ( 3, с, можно)

При левом внешнем соединении таблиц table1 и table2 первичных ключей получаются следующие результирующие триплеты (в том же формате, что и выше): (1, a, fun), (2, b, NULL), (3, c, can)

Правое внешнее соединение table1 к table2 на первичных ключах приведет к следующим результирующим триплетам (в том же формате, что и выше): (1, a, fun), (3, c, can), (4, NULL, случается)

Я надеюсь, что это хорошо объясняет концепцию.


4

Позвольте мне попытаться описать это немного более интуитивно.

Внутреннее соединение показывает пользователей, которые имеют один или несколько телефонов вместе с их телефонными номерами.

Левое внешнее объединение дополнительно перечисляет тех «пользователей», у которых нет телефона.


4

Поскольку вы спросили, когда что использовать, вот сценарий с запросами - выберите, какой использовать в зависимости от требования.

Данные:

Таблица Users имеет 10 записей. Таблица Phoneno имеет 6 записей (с отношением 1: 1, что означает, что запись в PhoneNo будет ссылаться только на одну запись в Users, и только одна запись в PhoneNo может ссылаться на данную запись в Users).

Требование 1: Показать всех пользователей с их номерами телефонов. Игнорировать пользователей без номера телефона.

Запрос:

SELECT u.uid, u.name, p.phonno 
  FROM user u 
INNER JOIN phones p ON p.uid = u.uid

Результат: показывает 6 пользователей, у которых есть номер телефона

Требование 2: Показать всех пользователей по их номеру телефона. Если у пользователя нет дисплея телефона «N / A» (недоступно)

Запрос:

SELECT u.uid, u.name, ifnull(p.phonno,'N/A') 
  FROM user u 
LEFT OUTER JOIN phones p ON p.uid = u.uid

Результат:

Показывает все 10 записей

Примечание: ifnull - это синтаксис MySql для преобразования нулевого значения. Я использовал эту функцию, чтобы двигатель БД показывал 'N / A', когда phonno равен нулю. Ищите соответствующую функцию, если вы используете какую-то другую СУБД. В SQL Server вы должны использовать CASEоператор.

Надеюсь, это поможет.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.