После добавления новой колонки запрос начал выдавать ошибку неоднозначного имени. Какой механизм SQL вызвал это изменение?
Ошибка возникает из-за неквалифицированной ссылки на столбец: после соединения несколько источников стали содержать столбец с одним именем, и SQL не может однозначно определить, какой из них нужен. Использование алиаса таблицы или явного имени источника устраняет неоднозначность.
В реляционном запросе результат соединения формируется из нескольких источников, поэтому одинаковые имена атрибутов могут присутствовать одновременно. Механизм квалифицированных имён появился как способ явно связать ссылку со схемой конкретного источника и сделать запрос устойчивее к изменениям структуры таблиц.
Обычное соединение по условию не объединяет одноимённые столбцы автоматически: в результирующем наборе могут присутствовать оба. Если запрос обращается к такому столбцу только по имени, разрешение ссылки становится неоднозначным.
Это опасно при изменении схемы. Запрос может не измениться текстуально, но добавление колонки в одну из таблиц внезапно превратит ранее однозначную ссылку в ошибочную. Ещё один риск — использование SELECT *: одинаковые имена могут появиться в выводе несколько раз и усложнить обработку результата приложением.
При разрешении ссылки SQL сначала определяет доступные источники текущего уровня запроса. Если неквалифицированное имя найдено более чем в одном источнике, сервер сообщает об неоднозначности, а не выбирает столбец произвольно.
Надёжный способ — использовать алиасы таблиц:
Здесь каждая ссылка однозначно относится к конкретному источнику. Алиасы особенно важны в само соединениях, длинных цепочках JOIN и запросах, которые должны переживать расширение схемы.
USING является отдельным случаем: указанный общий ключ представляется во внешнем результате как один столбец. Но это не означает, что любые одноимённые столбцы автоматически объединяются. При соединении через ON источники сохраняют свои отдельные столбцы, даже если их значения совпадают.
Квалификация не меняет кардинальность соединения и не устраняет дубликаты строк. Она влияет именно на разрешение ссылок и делает намерение запроса явным. Для публичных отчётов также желательно задавать собственные имена выходных столбцов вместо зависимости от имён из SELECT *.
В отчёте соединены customers и orders. Изначально только у клиентов был столбец status, поэтому ссылка на status работала. Позже в orders добавили собственный статус заказа, и тот же запрос стал завершаться ошибкой неоднозначного имени.
Вариант с сохранением неквалифицированной ссылки плох: он не выражает, какой статус нужен, и снова сломается при следующем изменении схемы. Вариант с SELECT * удобен для быстрого исследования, но создаёт дублирующиеся имена и нестабильный контракт результата.
Выбранное решение — явно указать источник и, при необходимости, переименовать поле в выходном наборе. Например, c.status AS customer_status и o.status AS order_status. Такой запрос сразу устранил ошибку и сделал смысл отчёта понятным потребителям данных.
Всегда ли SELECT * приводит к ошибке при одинаковых именах столбцов?
Нет. SELECT * может вернуть несколько столбцов с одинаковыми именами или метками; ошибка обычно возникает при неквалифицированном обращении к конкретному имени, когда оно неоднозначно. Поэтому отсутствие ошибки не означает, что результат удобен или безопасен для дальнейшей обработки.
Устраняет ли алиас таблицы дублирование имён в результате?
Нет. Алиас только квалифицирует ссылки внутри запроса. Если выбраны оба одноимённых столбца, они оба останутся в результирующем наборе; для понятного внешнего контракта нужно дополнительно задать разные выходные алиасы.
Чем квалификация отличается от USING?
Квалификация выбирает конкретный столбец конкретного источника, например столбец левой или правой таблицы. USING задаёт общий ключ соединения и формирует для него одну результирующую колонку, поэтому это не просто сокращённая запись квалифицированной ссылки: она влияет и на структуру результата.