2011-11-03 128 views
3

我最近在鏈接到SQL Server後端的表中查找錯誤的數據。我跑下面的查詢:MS Access/SQL Server Len()Brain Teaser

SELECT Len(MyField) AS FieldLength, "#" & MyField & "#" AS FieldContents 
FROM MyTable 
WHERE Len(MyField) <> 10 

我得到了以下結果:

FieldLength FieldContents 
----------------------------- 
10    #M1023-324 # 
10    #X3253-215 # 

於是告訴查詢中明確不返回長度爲10場後,它返回幾條記錄長度爲10的字段。所有的字段都有尾隨空格。

我弄清楚發生了什麼,它可以輕鬆地將一個毫無防備的開發人員/數據庫管理員(像我一樣)絆倒。那麼誰知道這裏發生了什麼?

+0

從您的提示下面,我懷疑這可能與ODBC設置或怪癖有關。 – HK1

回答

2

@Andriy M獲獎。正如他正確猜測的那樣,SQL Server處理WHERE子句,MS Access處理SELECT子句

通常這種悄無聲息,但的Transact-SQL LEN()修剪尾隨空白之前計數的字符,而VBA Len()功能不。請閱讀下面的完整說明。


我跑的SQL Server Profiler來看看有什麼MS Access已實際發送幕後,這裏就是我的了:

SELECT "dbo"."MyTable"."MyTableID" 
FROM "dbo"."MyTable" 
WHERE NOT(({fn length("MyField")}= 10)) 

上面的查詢返回的所有的匹配記錄的主鍵標準Len(MyField) <> 10{fn length()}ODBC Canonical Function

MS SQL Server使用自己的Len() function實現了{fn length()}規範函數。正如@Sir Crispalot在他的回答中指出的那樣,Transact-SQL Len函數修剪尾隨空格。所以在MS SQL Server中,Len('M1023-324 ') = 9。當然,在VBA中,Len("M1023-324 ") = 10

如果你仔細看看上面的查詢,你會發現它實際上並沒有返回我在原來的SELECT語句中請求的字段。相反,它只是返回足夠的信息(即主鍵字段)爲MS Access來請求完整的記錄,因爲它需要它們。

這是出於性能原因。如果我的查詢返回了30,000行並且每行有三十個字段,如果我在數據表中一次只顯示10行,那麼從SQL Server中獲取所有信息是沒有意義的。所以Access所做的就是獲取所有這些主鍵,然後一次從SQL Server請求單個記錄。此外,它實際上在SQL Server中創建臨時存儲過程,以執行它以返回這些單獨的行。我現在正在轉向脫離主題,但如果您有機會使用SQL Server Profiler,那麼值得做一些實驗來了解Access在幕後實際執行的操作。

無論如何,在SELECT子句中,MS Access只從SQL Server請求字段本身的內容。也就是說,它要求MyField而不是'#' & MyField & '#'。這也意味着它要求MyField而不是Len(MyField)

最終的結果是SQL Server執行篩選操作(WHERE子句)的計算,MS Access執行顯示操作(SELECT子句)的計算。而由於Len()功能在每個環境的行爲稍有不同,我們最終有一些什麼會考慮一個非常混亂的結果:

10 <> 10 

但它使我感覺良好。

+0

+1。整蠱,並且很高興知道! –

0

我重現了where子句的怪異行爲,所以查看了文檔。

MSDN摘自 - 「返回指定字符串表達式的字符,不包括尾隨空白的數量。」

因此,根據SQL「M1023-324」是長度9.

仍然沒有解釋爲什麼他們都在第一列中具有10個。我無法重現那一點!

+0

我可能沒有完全清楚在我的問題,但我從MS Access內運行此查詢。 MyTable錶鏈接到一個位於SQL Server後端的表中。 – mwolfe02

+0

這是一個提示;) – mwolfe02

+0

所以你發佈一個問題,你已經知道答案?!這對我來說是新的! –

0

看到你的提示後:是不是因爲Sql Server中的字段是char而不是varchar?

+0

這是一個迂迴的方式,這確實導致了這個問題。該字段實際上是一個varchar字段,但在其生命早期它是一個char字段。每個記錄應該有10個字符,因此它被設置作爲一個char(10)字段,一些流氓數據小於10個字符並引入了尾隨的空白,稍後當需求改變時,字段被轉換爲varchar(15)字段。帶有空白的數據位仍然存在。 – mwolfe02