就像在CASE语句中一样,未按预期评估
给定此数据:
CREATE TABLE tmpTable( fldField varchar(10) null); INSERT INTO tmpTable SELECT 'XXX' UNION ALL SELECT 'XXX' UNION ALL SELECT 'ZZZ' UNION ALL SELECT 'ZZZ' UNION ALL SELECT 'YYY' SELECT CASE WHEN fldField like 'YYY' THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable
预期结果集为:
XXX
XXX
XXX
XXX
OTH
什么情况会导致SQL Server 2000找不到" YYY"?并返回以下内容作为结果集:
XXX
XXX
XXX
XXX
XXX
问题出在诸如" YYY"之类的问题上,我发现了其他编写方法来使其工作,但我想知道为什么这种确切的方法不起作用。另一个困难是,它在我的大多数SQL Server 2000环境中都有效。我需要找出它们之间的不同之处。谢谢你的帮助。
解决方案
我们没有指定要选择的内容,而是针对CASE进行检查...
SELECT CASE fldField WHEN 'YYY' THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable
fldField ='%YYY%'`怎么样?
它在我的SQL 2005安装中按预期工作。如果它可以在其他计算机上运行,则听起来环境有所不同。尝试在SQL Server Management Studio中比较连接属性,以了解一个有效的连接和一个无效的连接,以查看是否可以找出区别。
我是一个Oracle人员,而不是一个SQL * Server人员,但是在我看来,我们应该是:
SELECT CASE WHEN fldField like '%YYY%' THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable
或者 ...
SELECT CASE WHEN fldField = 'YYY' THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable
第二个是我要走的方向,至少在Oracle平等中,解决起来快于同类。
当我们使用LIKE而不指定任何搜索条件时,其行为类似于=比较。在示例中,我希望它可以正常工作。在实际数据中,数据中可能有一个隐藏的(不可打印的)字符(考虑回车,换行,制表符等。)。
看一下这个例子...
Declare @tmpTable TABLE( fldField varchar(10) null); INSERT INTO @tmpTable SELECT 'XXX' UNION ALL SELECT 'XXX' UNION ALL SELECT 'ZZZ' UNION ALL SELECT 'ZZZ' UNION ALL SELECT 'YYY' UNION ALL SELECT 'YYY' + Char(10) SELECT CASE WHEN fldField like 'YYY' THEN 'OTH' ELSE 'XXX' END AS YourOriginalTest, CASE WHEN fldField like 'YYY%' THEN 'OTH' ELSE 'XXX' END AS newField FROM @tmpTable
我们会注意到,我添加的最后一条数据是YYY和换行符。如果选择此数据,我们将不会注意到数据中的换行符,但它在那里,因此LIKE条件(相当于一个相等条件)不匹配。
常见的"隐藏"字符是制表符,回车符和换行符。要确定这是否引起问题...
Select * From Table Where Column Like '%[' + Char(10) + Char(9) + Char(13) + ']%'
我在SQL 2000框中运行代码,并得到了相同的结果。不仅如此,而且当我运行一些其他代码进行测试时,我得到了一些非常奇怪的结果:
CREATE TABLE dbo.TestLike ( my_field varchar(10) null); GO CREATE CLUSTERED INDEX IDX_TestLike ON dbo.TestLike (my_field) GO INSERT INTO dbo.TestLike (my_field) VALUES ('XXX') INSERT INTO dbo.TestLike (my_field) VALUES ('XXX') INSERT INTO dbo.TestLike (my_field) VALUES ('ZZZ') INSERT INTO dbo.TestLike (my_field) VALUES ('ZZZ') INSERT INTO dbo.TestLike (my_field) VALUES ('YYY') GO SELECT my_field, case my_field when 'YYY' THEN 'Y' ELSE 'N' END AS C2, case when my_field like 'YYY' THEN 'Y' ELSE 'N' END AS C3, my_field FROM dbo.TestLike GO
我的结果:
my_field C2 C3 my_field ---------- ---- ---- ---------- N XXX N XXX N XXX N XXX Y YYY N YYY N ZZZ N ZZZ N ZZZ N ZZZ
注意my_field在同一行中有两个不同的值吗?我已经在这里的办公室请其他人进行快速测试。对我来说似乎是个虫子。
真是个可爱的错误。我想我知道原因。如果我是对的,那么我们将获得以下期望的结果:
SELECT CASE WHEN fldField like 'YYY ' -- 7 spaces THEN 'OTH' ELSE 'XXX' END as newField from tmpTable
错误在于varchar(10)的行为类似于char(10)的行为。至于为什么不这样,我们将需要了解一个古老的琐事问题,即两个没有元字符的字符串如何可以= =但又不能彼此相似。
问题是内部应将char(10)填充空格。 like运算符不会忽略这些空格。对于char,应该使用=运算符。内存告诉我,Oracle通常会忽略字符串的空格。 Postgres在转换方面有一些技巧。我没有使用过SQL * Server,所以无法告诉我们它是如何做到的。
检查服务包。将我的SQL 2000 box升级到SP4之后,我现在可以根据情况获得正确的值。
我仍然可以得到我在较早的文章中报告的交换数据:(
如果我们执行SELECT @@ version我们应该得到8.00.2039. 任何小于该版本的版本号,都应安装SP4.