Неоднозначное имя столбца — это правда?

#sql #tsql

#sql #tsql

Вопрос:

Если я хочу написать запрос с простым соединением, я могу сделать это:

 select * from customer c
join order o
on c.customerid = o.customerid
where c.customerid = 100
 

и все это работает нормально. В этом запросе есть причина, по которой я должен указать псевдоним таблицы — ie. c.customerid ? Почему я не могу просто написать это:

 select * from customer c
join order o
on c.customerid = o.customerid
where customerid = 100
 

Я получаю сообщение об ошибке Ambiguous column name 'customerid' . В этом случае, когда в предложении WHERE есть только один столбец, и это столбец, к которому я присоединяюсь, действительно ли это «неоднозначно»? Или это просто для соответствия стандарту ansi (я предполагаю здесь — я не знаю, соответствует ли он требованиям) и для поощрения хороших соглашений о кодировании?

Ответ №1:

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

 DECLARE @customer TABLE
(customerid CHAR(3) COLLATE Latin1_General_CI_AS)

INSERT INTO @customer VALUES('FOO');

DECLARE @order TABLE
(customerid CHAR(3) COLLATE Latin1_General_CS_AS)

INSERT INTO @order VALUES('FOO');


SELECT * 
FROM @customer c
JOIN @order o
ON c.customerid = o.customerid COLLATE Latin1_General_CS_AS
WHERE c.customerid = 'Foo' /*Returns 1 row*/

SELECT * 
FROM @customer c
JOIN @order o
ON c.customerid = o.customerid COLLATE Latin1_General_CS_AS
WHERE o.customerid = 'Foo' /*Returns 0 rows*/
 

Комментарии:

1. @Martin Smith — спасибо за а) ответ на вопрос и б) предоставление интересного примера

Ответ №2:

Исключение псевдонима таблицы действительно приводит к неоднозначной ссылке на столбец. Просто создайте свой join a left join , и вы сразу поймете, почему:

 select * from customer c
left join order o
on c.customerid = o.customerid
where customerid = 100 -- here, the semantics are quite different
 

Другая причина: один столбец может иметь тип INTEGER , другой — тип SMALLINT . Какой из них использовать для фильтра? (Это может повлиять на план выполнения). Еще лучший пример приведен Мартином Смитом

Таким образом, в целом, вы бы мало что выиграли, сделав SQL более «снисходительным», в то же время вводя новые источники ошибок. Что вы могли бы сделать с некоторыми базами данных (не SQL Server), однако это:

 select * from customer c
join order o
using (customerid)
where customerid = 100
 

Или это (если customerid является единственным общим именем столбца)

 select * from customer c
natural join order o
where customerid = 100
 

Комментарии:

1. 1 SQL Server не поддерживает using or natural join , и я не уверен, как тип данных влияет на вещи? В INNER JOIN любом случае будут возвращены только те значения, которые вписываются в диапазон smallint .

2. @MartinSmith: Вы правы, спасибо. Тип данных, вероятно, повлияет на план выполнения.

Ответ №3:

Вы получаете ошибку, потому что столбец customerid существует как в таблицах order, так и в таблицах customer, и SQL не знает, к какому столбцу должно быть применено условие.

Ответ №4:

После JOINing двух таблиц результирующая таблица содержит 2 столбца с одинаковым именем customerid . Итак, вам нужно указать в WHERE предложении, какой столбец использовать, добавив имя таблицы в качестве префикса.

Ответ №5:

Хорошо…вы знаете, что результирующий набор будет содержать только записи с точно такими же customerid , однако сервер базы данных этого не делает, потому что он не «понимает», что вы указываете. И если у вас было соединение, в котором оба идентификатора клиентов не совпадают в результирующем наборе, вы будете счастливы, что сервер их различает. 😉

Ответ №6:

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