SQL 服务器是否在查询时自动 trim nvarchar 字段?

Does SQL Server automatically trim nvarchar fields upon query?

我有这个查询:

select '[' + p.Firstname + ']' from Person p
where p.Firstname = 'Johanne'

在 table 中,我有多个人有这个名字,有些人在值上有尾随 space(值插入错误,将被更正)。

为什么这个查询会给我带来这个结果(我插入括号以可视化 spaces):

[Johanne]
[Johanne ]
[Johanne ]
[Johanne]

这是配置问题吗?真正的查询来自 entity framework 6,但这个例子也是这样做的。我该如何预防?

谢谢!

编辑:我可以使用 EF6 和 System.Data.Entity.SqlServer.SqlFunctions.DataLength 方法使其工作,如下所示:

ctx.Person.FirstOrDefault(p => p.FirstName == "Johanne" && SqlFunctions.DataLength(p.FirstName) == "Johanne".Length);

SQL 服务器遵循 ANSI/ISO SQL-92 规范(第 8.2 节,通用规则 #3)关于如何将字符串与 space 进行比较。 ANSI 标准要求对比较中使用的字符串进行填充,以便它们的长度在比较之前匹配。填充直接影响 WHERE 和 HAVING 子句谓词和其他 Transact-SQL 字符串比较的语义。例如,Transact-SQL 认为字符串 'abc' 和 'abc ' 对于大多数比较操作是等价的。

此规则的唯一例外是 LIKE 谓词。当 LIKE 谓词表达式的右侧具有尾随 space 的值时,SQL 服务器不会在比较发生之前将两个值填充到相同的长度。因为根据定义,LIKE 谓词的目的是促进模式搜索而不是简单的字符串相等性测试,这并不违反前面提到的 ANSI SQL-92 规范的部分。

参见:https://support.microsoft.com/en-us/topic/inf-how-sql-server-compares-strings-with-trailing-spaces-b62b1a2d-27d3-4260-216d-a605719003b0

我不确定在 EF 中,但在 TSQL 中我使用 DataLength

DataLength

DataLength 将 return 包括尾随空格的长度
Len 将 return 不包括尾随空格的长度

and DataLength(p.Firstname) = Len('Johanne')  

您可以在 Sql 中创建一个新视图并将该视图映射回 EF 对象。视图可以包含字段的长度,在 select 中使用 DataLength,您知道您想要匹配,然后您可以在使用 EF 时在 where 子句中对其进行过滤。 或者,您可以创建一个 Sql Stored Proc,它使用不带通配符的 LIKE 进行比较(产生所需的结果)并将其映射回您的代码并在 EF 的 Where 语句中调用它。


使用视图

Create View MyCustomView
AS
SELECT [column1,column2,etc], DATALENGTH(FirstName) AS FirstNameLength
FROM Person
GO

那么您的 EF 将是:

Persons.Where(p => p.FirstNameLength == "Johanne".Length && p.FirstName == "Johanne");

使用存储过程

CREATE PROCEDURE [dbo].[GetPersons]
firstName int = null
AS
BEGIN
SET NOCOUNT ON;
select [your fields here]
from persons
where FirstName like @firstName
END

在 C# 中确保映射正确,然后

this.Database.SqlQuery<Person>("GetPersons","Johanne");

EF6 还支持在执行前直接编辑 DbContext 中的 sql。您可以开发一些自定义代码,在特定情况下用 like 替换 =,但在您这样做之前先尝试上面的代码可能更容易。