#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
ornatural join
, и я не уверен, как тип данных влияет на вещи? ВINNER JOIN
любом случае будут возвращены только те значения, которые вписываются в диапазонsmallint
.2. @MartinSmith: Вы правы, спасибо. Тип данных, вероятно, повлияет на план выполнения.
Ответ №3:
Вы получаете ошибку, потому что столбец customerid существует как в таблицах order, так и в таблицах customer, и SQL не знает, к какому столбцу должно быть применено условие.
Ответ №4:
После JOINing
двух таблиц результирующая таблица содержит 2 столбца с одинаковым именем customerid
. Итак, вам нужно указать в WHERE
предложении, какой столбец использовать, добавив имя таблицы в качестве префикса.
Ответ №5:
Хорошо…вы знаете, что результирующий набор будет содержать только записи с точно такими же customerid
, однако сервер базы данных этого не делает, потому что он не «понимает», что вы указываете. И если у вас было соединение, в котором оба идентификатора клиентов не совпадают в результирующем наборе, вы будете счастливы, что сервер их различает. 😉
Ответ №6:
Ошибка неоднозначного столбца возникает только тогда, когда нам нужно выполнить какую-то операцию с полем, которое содержится в более чем одной таблице, поэтому в этом случае SQL не может распознать, из какой таблицы ему нужно работать.