Объясните механизм естественного соединения: какие атрибуты определяют пары строк в его результате?
Естественное соединение сопоставляет строки по всем атрибутам, которые имеют одинаковые имена в обоих отношениях. В результат попадает пара строк только при равенстве каждого общего атрибута, а общие атрибуты представлены один раз.
В SQL это соответствует NATURAL JOIN, но его поведение зависит от имён столбцов, поэтому изменение схемы может незаметно изменить результат.
В реляционной алгебре соединение нужно для построения нового отношения из связанных кортежей разных отношений. Естественное соединение стало удобной формой записи случая, когда связь определяется совпадающими атрибутами с одинаковыми именами.
Такой подход уменьшает повторение явно заданных условий, но переносит часть логики запроса в соглашение об именовании. Для промышленных запросов это часто менее безопасно, чем явное указание условия соединения.
Предположим, есть отношения Заказы и Клиенты, у которых общий атрибут КодКлиента. Естественное соединение должно оставить только пары строк с одинаковым значением КодКлиента и не дублировать этот атрибут в схеме результата.
Риск возникает, если в таблицах появляется другой столбец с таким же именем, например Статус. Он автоматически станет дополнительным условием соединения, хотя разработчик мог не считать его частью связи. В результате строки могут исчезнуть без явной ошибки синтаксиса.
Механизм естественного соединения можно разложить на три шага:
Если общих атрибутов нет, естественное соединение вырождается в декартово произведение: каждая строка одного отношения сочетается с каждой строкой другого. Если общих атрибутов несколько, условие является конъюнкцией равенств по всем ним.
В классической реляционной алгебре отношения являются множествами, поэтому одинаковые результирующие кортежи не дублируются. SQL обычно работает с мультимножествами: совпадающие строки могут повторяться, если это не устранено отдельным DISTINCT или другим оператором.
В SQL имена столбцов имеют техническое значение для NATURAL JOIN, а не только документируют предметную область. Кроме того, сравнение с NULL не даёт истинного результата: оно даёт UNKNOWN, поэтому строки с NULL в общем столбце не образуют совпадение естественного соединения.
Минимальный пример:
Если обе таблицы содержат только общий столбец КодКлиента, соединение использует именно его. Если позже в обеих таблицах появится общий Статус, SQL начнёт требовать совпадения и КодКлиента, и Статус.
На практике чаще выбирают явное соединение по именованным столбцам. Оно длиннее, зато устойчивее к добавлению столбцов и яснее выражает бизнес-правило.
В отчёте нужно было сопоставить платежи с клиентами по идентификатору клиента. Изначально у таблиц был один общий столбец, поэтому NATURAL JOIN возвращал ожидаемое число строк.
Рассматривались два варианта. Сохранить естественное соединение было проще и короче, но оно зависело от будущих изменений схемы. Переписать запрос с явным указанием ключей требовало небольшого изменения, зато исключало случайное добавление новых условий.
Выбрали явное соединение по идентификатору клиента. После этого добавление одноимённого Статус не изменяло состав связанных строк, а изменение логики связи стало видимым непосредственно в запросе. Это снизило риск тихого неполного отчёта.
1. Что произойдёт, если у двух отношений несколько одноимённых атрибутов?
Все такие атрибуты участвуют в условии одновременно. Например, общие КодКлиента и Регион означают требование равенства обоих значений, а не выбор одного из них. Поэтому естественное соединение может вернуть меньше строк, чем ожидается при мысленной проверке только по идентификатору.
2. Чем естественное соединение отличается от соединения по одному внешнему ключу?
Естественное соединение выводит условие из всех совпадающих имён, а соединение по внешнему ключу использует конкретно выбранные атрибуты. Внешний ключ может быть составным, но его состав определяется ограничением и моделью данных, а не случайным совпадением имён столбцов.
3. Что изменится при переименовании общего атрибута только в одном отношении?
Атрибут перестанет считаться общим, поэтому естественное соединение больше не будет использовать его для сопоставления. Если других одноимённых атрибутов нет, результат превратится в декартово произведение; если они есть, соединение будет выполняться только по ним. Это одна из причин считать NATURAL JOIN хрупким для поддерживаемого кода.