@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规范函数。
MS SQL Server使用自己的
Len()
函数来实现
{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
但这对我来说是很有道理的。