2010-01-21 18 views
9

當我運行此查詢爲什麼在子查詢中沒有「無效的列名稱XYZ」錯誤;儘管列名不在子查詢表中?

SELECT CustomerId FROM Stocks.dbo.Suppliers 

它給了我這個錯誤。無效的列名稱'CustomerId'。此錯誤有效,因爲「供應商」表中沒有列CustomerId;但是當我在子查詢中使用相同的查詢時,它不會給出任何錯誤E.g.

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

這裏我期待同樣的錯誤「無效的列名」,但查詢運行沒有任何錯誤。

完全限定名稱只是約定兩個dbs都在同一臺服務器上。

CustomerId在SomeOtherDb.dbo.Customer表中存在,但不存在於子查詢中。

這是爲什麼?這是子查詢嗎?

謝謝。

+0

拋出無效列錯誤在我在任的局面。完全限定名稱只是約定還是通過鏈接服務器? – Andrew 2010-01-21 15:54:00

+0

完全限定的名稱只是一個約定。兩個數據庫都在同一臺服務器上。 – Kashif 2010-01-21 16:00:32

回答

13

子查詢繼承外部查詢的列。

我想你的SomeOtherDb.dbo.Customer確實有一個CustomerId列(這也可能來自這些名字)。

那麼這也可能意味着你沒有用子查詢來處理你想要做的事情 - 如果子查詢中的表沒有CustomerId列(並且看起來如此,否則在沒有錯誤時不會有錯誤子查詢本身運行),那麼子查詢將選擇並返回外部CustomerId,並且由於這是子查詢中唯一的列,所以子查詢是無用的。

+0

是的,你是對的SomeOtherDb.dbo.Customer有CustomerId列。 – Kashif 2010-01-21 16:01:46

+6

我已經碰到過幾次了,雖然答案很有意義,但我認爲這是SQL Server中的糟糕設計(無論它是否完全實現了ISO SQL標準)。我認爲當引用父查詢中的列時,要求子查詢使用別名會更安全。我的同事在錯誤地更新生產表中的所有行時遇到了相關的悲劇,這是由於上面子查詢中的拼寫錯誤造成的。隨之而來的是歡鬧(並從備份恢復): – 2013-06-04 22:40:29

+0

通過爲每列明確定義表(或表別名)是一種好的做法:它將避免您的子查詢從不正確的表中獲取列,並且還會在常規聯接上(不包括子查詢) )將避免名稱衝突,以防有人創建新列。 – drizin 2016-09-21 14:06:32

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 

這個查詢,當使用當然可能的連接構造時,將始終執行和原來一樣或更好 - 同時還有避免上面那個討厭問題的額外好處。因爲在這個構造中你自然會使用表名,在出現問題時它會更加明顯,例如等號兩邊的表名相同。子查詢吸引我,我對他們的永久討伐。

(這麼說,我知道很多人都在反對走樣討伐,我在上面用來簡化/凝結代碼:))