2010-01-21 1 views
9

Когда я запускаю этот запросПочему ошибка «Недопустимое имя столбца XYZ» в подзапросе; хотя имя столбца не в таблице подзапроса?

SELECT CustomerId FROM Stocks.dbo.Suppliers 

Это дает мне эту ошибку. Недопустимое имя столбца «CustomerId». Эта ошибка действительна, поскольку в таблице «Поставщики» нет столбца CustomerId; но когда я использую тот же запрос в подзапросе, он не дает никакой ошибки.

SELECT * 
    FROM SomeOtherDb.dbo.Customer 
WHERE CustomerId In(SELECT CustomerId 
         FROM Stocks.dbo.Suppliers) 

Здесь я ожидаю ошибку «Недопустимое имя столбца», но запрос выполняется без ошибок.

Полностью квалифицированное имя - это просто соглашение, и обе стороны находятся на одном сервере.

CustomerId существует в SomeOtherDb.dbo.Customer таблице, но не в подзапросе.

Почему такое поведение? Это что-то с подзапросом?

Спасибо.

+0

Приводит неверном столбца на меня в любой ситуации. Является ли полностью квалифицированное имя просто условным или связанным сервером? – Andrew

+0

Полностью квалифицированное имя - это просто конвенция. Обе базы данных находятся на одном сервере. – Kashif

ответ

13

Подзапросы наследуют столбцы из внешних запросов.

Я предполагаю, что у вашего SomeOtherDb.dbo.Customer действительно есть столбец CustomerId (что также кажется вероятным из имен).

Который также, вероятно, означает, что вы не делаете с подзапросом то, что вы хотите с ним делать - если в таблице в подзапросе нет столбца CustomerId (и, похоже, это так, в противном случае не было бы ошибки, если запуск подзапроса сам по себе), тогда подзапрос выбирает и возвращает внешний CustomerId, и поскольку это единственный столбец в подзапросе, подзапрос бесполезен.

+0

Да, вы правы SomeOtherDb.dbo.Customer имеют столбец CustomerId. – Kashif

+6

Я сталкивался с этим сам несколько раз, и хотя ответ имеет смысл, я думаю, что это плохой дизайн в SQL Server (независимо от того, полностью ли он реализует стандарт ISO SQL). Я думаю, было бы гораздо безопаснее требовать, чтобы подзапросы использовали псевдоним, когда ссылались на столбцы в родительском запросе. Мой коллега испытал связанную трагедию, когда он по ошибке обновил все строки в производственной таблице из-за опечатки в подзапросе, как описано выше. Hilarity (и восстановление из резервных копий): –

+0

Явным образом определение таблицы (или псевдонима таблицы) для каждого столбца является хорошей практикой: это позволит избежать подзапросов в получении столбцов из неправильных таблиц, а также на регулярных объединениях (без подзапросов) избежит конфликтов имен, если кто-то создает новые столбцы. – drizin

1

Ответ на ваш вопрос («почему нет ошибки») выше, но, возможно, небольшая помощь в том, как избежать этого типа проблемы в будущем: вместо использования подзапроса для этого используйте левое соединение:

SELECT C.* 
FROM SomeOtherDb.dbo.Customer AS C 
LEFT JOIN Stocks.dbo.Suppliers AS S ON C.CustomerId = S.CustomerId 
WHERE S.CustomerID Is Null 

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

(то есть, я знаю много людей на крестовый поход против наложения спектров, который я использовал выше, чтобы упростить/конденсироваться код :))