#sql #join #natural-join
#sql #Присоединиться #естественное соединение
Вопрос:
Я читаю о ЕСТЕСТВЕННОЙ сокращенной форме для SQL joins и вижу некоторые ловушки:
- он просто автоматически принимает все пары столбцов с одинаковыми именами (используйте USING для указания явного списка столбцов)
- если добавлен какой-то новый столбец, то выходные данные соединения также могут быть «неожиданно» изменены, что может быть не так очевидно (даже если вы знаете, как работает NATURAL) в сложных структурах
Ответ №1:
NATURAL JOIN
синтаксис не соответствует шаблону:
- Цель запроса менее очевидна;
- столбцы, используемые приложением, не ясны
- используемые столбцы могут измениться «неожиданно»
- Синтаксис идет вразрез с правилом модульности, об использовании строгой типизации, когда это возможно. Явный почти повсеместно лучше.
Из-за этого я не рекомендую синтаксис ни в какой среде.
Я также не рекомендую смешивать синтаксис (т. Е. использовать как NATURAL JOIN
, так и явный синтаксис ВНУТРЕННЕГО / ВНЕШНЕГО СОЕДИНЕНИЯ) — сохраняйте согласованный формат кодовой базы.
Комментарии:
1. 1 для запроса менее очевидно. Чтение намного сложнее, чем запись.
2. Я понимаю всю вашу точку зрения. Да, я написал «в производственной среде» намеренно, поэтому я согласен, что в этом смысле мы можем рассматривать NATURAL как антишаблон, потому что это сложно использовать.
3. @onedaywhen: У меня возникли проблемы со статьей в Википедии по этому поводу, проиллюстрированной ошибкой в описании тета-соединения «Price = Цена», которая показывает, как традиционно реляционная алгебра не придавала большого значения нескольким таблицам, разделяющим имя атрибута, при этом отличающимся по смыслу. Вы всегда можете переписать a
NATURAL JOIN
с помощьюINNER JOIN
, но есть много случаев, когда вы не можете реализоватьINNER JOIN
с помощьюNATURAL JOIN
. В лучшем случае это создаетNATURAL JOIN
синтаксический сахар. Это работает в математике, поскольку в математике вы предполагаете, что одно и то же имя всегда имеет одинаковое значение.4. @onedaywhen: Я последовательно демонстрировал, что у вас на самом деле нет никаких причин, связанных с заданным вопросом, для того, чтобы понизить голос, неважно, что у вас еще нет возражений против любого другого ответа. Никто другой с вами не согласен, и все больше людей пытаются оспорить вашу позицию по этому вопросу. Похоже, вы ненавидите аккаунты с высокой репутацией, но не желаете ничего делать для улучшения своей репутации — где ваш ответ? Отрицательные голоса можно поменять местами, но вы предпочли бы быть тупым — вам нравится мое внимание. Вы «двигаетесь дальше», потому что на каком-то уровне вы, наконец, понимаете свое поведение.
5. @OMG Ponies: (извините за комментарий с шумом) Хорошо сказано. Однажды ко мне обращались так же: сплошная критика, ничего конструктивного. Звучит как академик, который на самом деле не использует SQL изо дня в день, а просто любит читать книги…
Ответ №2:
Эти «ловушки», которые, похоже, выступают против естественных соединений, работают в обоих направлениях. Предположим, вы добавляете новый столбец в таблицу A, полностью ожидая, что он будет использоваться при объединении с таблицей B. Если вы знаете, что каждое соединение A и B является естественным соединением, то все готово. Если каждое соединение явно использует USING, то вам нужно отследить их все и изменить. Пропустите одно, и появится ошибка.
Используйте ЕСТЕСТВЕННЫЕ соединения, когда семантика таблиц предполагает, что это правильно. Используйте явные критерии объединения, когда хотите убедиться, что объединение выполняется определенным образом, независимо от того, как могут изменяться определения таблиц.
Комментарии:
1. Без сомнения, NATURAL является более «скрыто-сложным», чем предложение strict USING или general ON (это некоторая причина избегать этого), но, как вы написали, это зависит от семантики. Я полагаю, что в большинстве случаев я хочу использовать USING или ON, чтобы быть уверенным, что именно так.
2. Да, я думаю, что в большинстве (но не во всех) случаях лучше быть явным.
Ответ №3:
Одна вещь, которая полностью разрушает NATURAL
меня, заключается в том, что в большинстве моих таблиц есть id
столбец, которые, очевидно, семантически все разные. Вы могли бы возразить, что наличие a user_id
имеет больше смысла, чем id
, но тогда вы в конечном итоге пишете такие вещи, как user.user_id
нарушение DRY . Кроме того, по той же логике у вас также должны были бы быть столбцы типа user_first_name
, user_last_name
, user_age
… (что также отчасти имеет смысл, учитывая, что оно будет отличаться, например, от session_age
)… Ужас.
Я буду придерживаться своего JOIN ... ON ...
, большое вам спасибо. 🙂
Ответ №4:
Я согласен с другими плакатами, что явное соединение следует использовать из соображений ясности, а также для того, чтобы легко разрешить переключение на «ВНЕШНЕЕ» соединение в случае изменения ваших требований.
Однако большинство ваших «ловушек» не имеют ничего общего с объединениями, а скорее являются недостатками использования «SELECT *» вместо явного именования требуемых столбцов «ВЫБЕРИТЕ a.col1, a.col2, b.col1, b.col2». Эти ловушки возникают всякий раз, когда используется список столбцов с подстановочными знаками.
Ответ №5:
Добавление дополнительной причины, не указанной ни в одном из ответов выше. В postgres (не уверен, что это относится к другим базам данных), если при использовании двух таблиц не найдено общих имен столбцов, NATURAL JOIN
тогда CROSS JOIN
выполняется. Это означает, что если у вас был существующий запрос, а затем вы должны были впоследствии изменить одно из имен столбцов в таблице, вы все равно получили бы набор строк, возвращаемых из запроса, а не ошибку. Если бы вместо этого вы использовали JOIN ... USING(...)
синтаксис, вы бы получили сообщение об ошибке, если бы объединяющего столбца больше не было.
В документации postgres есть примечание на этот счет:
Примечание: ИСПОЛЬЗОВАНИЕ достаточно безопасно от изменений столбцов в объединенных отношениях, поскольку объединяются только перечисленные столбцы. ЕСТЕСТВЕННОЕ соединение значительно более рискованно, поскольку любые изменения схемы в любом отношении, которые приводят к появлению нового соответствующего имени столбца, приведут к объединению и этого нового столбца.
Ответ №6:
Вы имеете в виду синтаксис, подобный этому:
SELECT *
FROM t1, t2, t3 ON t1.id = t2.id
AND t2.id = t3.id
По сравнению с этим:
SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id
AND t2.id = t3.id
Я предпочитаю синтаксис 2nd, а также форматирую его по-другому:
SELECT *
FROM T1
LEFT OUTER JOIN T2 ON T2.id = T1.id
LEFT OUTER JOIN T3 ON T3.id = T2.id
В этом случае очень ясно, к каким таблицам я присоединяюсь и какое предложение ON я использую для их объединения. Используя этот первый синтаксис, слишком легко не ввести правильное соединение и получить огромный набор результатов. Я делаю это, потому что я склонен к опечаткам, и это моя страховка от этого. Кроме того, это визуально упрощает отладку.
Комментарии:
1. Нет — первый пример — синтаксис ANSI-89, последний — ANSI-92.
NATURAL JOIN
также является синтаксисом ANSI-92. Простите, я думал, что первым был ANSI-89, но это гибрид двух, и я сомневаюсь, что он поддерживается на чем-либо, кроме MySQL.2. Спасибо, но я сомневаюсь в ЕСТЕСТВЕННОМ (неявном «полном» списке соответствия столбцов). Я имею в виду что-то вроде SELECT * FROM t1 ЕСТЕСТВЕННОГО ЛЕВОГО СОЕДИНЕНИЯ t2;
3. О, интересно, я раньше не видел этого ключевого слова NATURAL. Извините за потраченный впустую ответ, но спасибо за новое ключевое слово.