Какой лучший способ объединиться за одним столом дважды? - PullRequest
97 голосов
/ 24 ноября 2010

Это немного сложно, но у меня есть 2 таблицы. Допустим, структура выглядит примерно так:

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

Таблицы могут объединяться на основе Table1.PhoneNumber1 -> Table2.PhoneNumber или Table1.PhoneNumber2 -> Table2.PhoneNumber.

Теперь я хочу получить набор результатов, который содержит PhoneNumber1, SomeOtherField, который соответствует PhoneNumber1, PhoneNumber2, и SomeOtherField, который соответствует PhoneNumber2.

Я подумал о двух способах сделать это: либо присоединиться к таблице дважды, либо присоединиться один раз с помощью ИЛИ в предложении ON.

Метод 1 :

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
   t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
   ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
   ON t3.PhoneNumber = t1.PhoneNumber2

Кажется, это работает.

Метод 2 :

Чтобы получить запрос, похожий на этот -

SELECT ...
FROM Table1
INNER JOIN Table2 
   ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
      Table1.PhoneNumber2 = Table2.PhoneNumber

Я еще не заставил это работать, и я не уверен, есть ли способ сделать это.

Какой лучший способ сделать это? Ни один из способов не кажется простым или интуитивным ... Есть ли более простой способ сделать это? Как обычно выполняется это требование?

Ответы [ 5 ]

134 голосов
/ 24 ноября 2010

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

Метод 1 , как вы описываете, это ваш лучший выбор.Это выглядит немного лаконично из-за схемы именования и коротких псевдонимов, но ... псевдонимы - ваш друг, когда дело доходит до объединения нескольких таблиц или использования подзапросов и т. Д.

Я бы просто очистил всебит:

SELECT t.PhoneNumber1, t.PhoneNumber2, 
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2

Что я сделал:

  • Не нужно указывать INNER - это подразумевается тем фактом, что вы не указали LEFT или RIGHT
  • Не используйте n-суффикс вашей первичной таблицы поиска
  • N-Суффикс псевдонимов таблицы, которые вы будете использовать несколько раз, чтобы сделать ее очевидной

* Односторонним образом администраторы баз данных избегают головной боли обновленияестественные ключи - не указывать первичные ключи и ограничения внешнего ключа, что еще больше усугубляет проблемы с плохим дизайном БД.Я действительно видел это чаще, чем нет.

4 голосов
/ 24 ноября 2010

Первый вариант хорош, если только Phone1 или (более вероятно) phone2 могут быть нулевыми. В этом случае вы хотите использовать левое соединение вместо внутреннего соединения.

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

2 голосов
/ 05 февраля 2016

У меня была проблема с отображением записи, даже если номер телефона отсутствует или только * (полная адресная книга).Поэтому я использовал LEFT JOIN, который берет все записи слева, даже если справа нет соответствующих записей.Для меня это работает в Microsoft Access SQL (они требуют скобок!)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
   t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM 
(
 (
  Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
 )
 LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;
2 голосов
/ 24 ноября 2010

Вы можете использовать UNION для объединения двух объединений:

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber1 = Table2.PhoneNumber
 UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
  FROM Table1
  JOIN Table2
    ON Table1.PhoneNumber2 = Table2.PhoneNumber
2 голосов
/ 24 ноября 2010

Первый метод - это правильный подход, и он будет делать то, что вам нужно.Однако с внутренними объединениями вы будете выбирать строки из Table1, только если оба телефонных номера существуют в Table2.Возможно, вы захотите сделать LEFT JOIN, чтобы были выбраны все строки из Table1.Если телефонные номера не совпадают, то SomeOtherField s будет нулевым.Если вы хотите убедиться, что у вас есть хотя бы один соответствующий телефонный номер, вы могли бы сделать WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

Второй метод может иметь проблему: что произойдет, если Table2 имеет и PhoneNumber1, и PhoneNumber2?Какой ряд будет выбран?В зависимости от ваших данных, внешних ключей и т. Д. Это может быть или не быть проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...