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


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

*Table1*
ID
PhoneNumber1
PhoneNumber2

*Table2*
PhoneNumber
SomeOtherField

таблицы могут быть объединены на основе таблицы 1.PhoneNumber1 - > Table2.Номер телефона или Таблица1.PhoneNumber2 - > Table2.Номер телефона.

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

Я думал о 2 способах сделать это-либо путем присоединения к таблице дважды, либо путем присоединения один раз с или в предложении 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 86

5 ответов:

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

Способ 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

что я сделал:

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

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

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

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

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

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

вы могли бы использовать 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

моя проблема была в отображение записи, даже если нет или существует только один номер телефона (полная адресная книга). Поэтому я использовал левое соединение, которое берет все записи слева, даже если нет соответствующего справа. Для меня это работает в 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;