我最近在链接到SQL Server后端的表中查找错误数据。我运行了以下查询:
SELECT Len(MyField) AS FieldLength, "#" & MyField & "#" AS FieldContents
FROM MyTable
WHERE Len(MyField) <> 10
我得到了以下结果:
FieldLength FieldContents
-----------------------------
10 #M1023-324 #
10 #X3253-215 #
因此,在特别告知查询不返回长度为10的字段后,它返回了几条长度为10的字段的记录。所有字段都有尾随空格。
我确实弄清楚发生了什么,这种事情很容易让一个毫无戒心的开发/ DBA(像我一样)绊倒。那么谁知道这里发生了什么?
答案 0 :(得分:2)
通常这会被忽视,但 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
但这对我来说非常有意义。
答案 1 :(得分:0)
我重现了where子句的奇怪行为,所以看了一下文档。
取自MSDN - “返回指定字符串表达式的字符数,不包括尾随空白。”
因此根据SQL,“M1023-324”的长度为9。
仍然没有解释为什么他们在第一列中都有10个。我无法重现那一点!
答案 2 :(得分:0)
看到你的提示之后:是不是因为Sql Server中的字段是char而不是varchar?