在T-SQL中,为什么操作符不适用于变量而是适用于文字?

时间:2017-03-30 17:02:59

标签: sql-server tsql

这是脚本:

第一个脚本:

declare @a char(10) = 'AA%'
declare @b char(10) = 'AA001'

if @b LIKE @a 
     print 'Equals' 
else 
begin 
     print 'Not equals' 
end

打印:

Not Equals

我原以为要打印Equals。但是下面的脚本在条件中不使用@a

第二个脚本:

declare @a char(10) = 'AA%'
declare @b char(10) = 'AA001'

if @b LIKE 'AA%' 
    print 'Equals' 
else 
begin 
    print 'Not equals' 
end

打印

Equals

那么为什么第一个脚本认为它们不相等但第二个脚本认为它们相等?

1 个答案:

答案 0 :(得分:7)

答案实际上很简单,但这是 big gotcha :这是因为char类型。

如果我们打印出2个变量:

print @a
print @b

输出将是(点表示空白空间):

AA%.......       
AA001.....   

因此第一个查询对两个变量执行like,并且尾随空白使它不相等,因为根据MSDN,从逻辑上讲,尾随空格(空格)是重要的:< / p>

  

如果查询中的比较是使用字符串LIKE&#39; abc&#39;返回所有行。 (abc没有空格),返回以abc开头且具有零个或多个尾随空格的所有行。 +   使用包含char和varchar数据的模式的字符串比较可能无法通过LIKE比较,因为数据的存储方式。

第二次查询

第二个查询的文字AA%的隐式类型为varchar,而AA001(其类型为char)将类似于AA%,它打印等于。为了重申文字的类型是varchar,我使用了这个查询:

SELECT SQL_VARIANT_PROPERTY('AA%', 'BaseType')

返回 varchar

更多信息

以下是来自MSDN的更多示例,以进一步明确:

以下示例将本地char变量传递给存储过程,然后使用模式匹配查找姓氏以指定字符集开头的所有员工。

-- Uses AdventureWorks  

CREATE PROCEDURE FindEmployee @EmpLName char(20)  
AS  
SELECT @EmpLName = RTRIM(@EmpLName) + '%';  
SELECT p.FirstName, p.LastName, a.City  
FROM Person.Person p JOIN Person.Address a ON p.BusinessEntityID = a.AddressID  
WHERE p.LastName LIKE @EmpLName;  
GO  
EXEC FindEmployee @EmpLName = 'Barb';  
GO  

FindEmployee过程中,不返回任何行,因为只要名称包含少于20个字符,char变量(@EmpLName)就包含尾随空格。因为LastName列是varchar,所以没有尾随空格。此过程失败,因为尾随空白很重要。 但是,以下示例成功,因为尾随空格未添加到varchar变量。

- 使用AdventureWorks

CREATE PROCEDURE FindEmployee @EmpLName varchar(20)  
AS  
SELECT @EmpLName = RTRIM(@EmpLName) + '%';  
SELECT p.FirstName, p.LastName, a.City  
FROM Person.Person p JOIN Person.Address a ON p.BusinessEntityID = a.AddressID  
WHERE p.LastName LIKE @EmpLName;  
GO  
EXEC FindEmployee @EmpLName = 'Barb';  

以下是结果集:

FirstName LastName City
---------- -------------------- ---------------
Angela Barbariol Snohomish
David Barber Snohomish
(2 row(s) affected)