就像在CASE声明中没有按预期进行评估

时间:2008-09-22 19:17:22

标签: sql sql-server

鉴于此数据:

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环境。我需要找出它们之间的不同之处。谢谢你的帮助。

9 个答案:

答案 0 :(得分:1)

我在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在同一行中有两个不同的值?我已经在办公室要求其他人给它一个快速测试。对我来说看起来像个错误。

答案 1 :(得分:1)

检查您的服务包。将我的SQL 2000框升级到SP4后,我现在可以根据您的情况获得正确的值。

我仍然收到我在之前的帖子中报告的交换数据:(

如果你SELECT @@version,你应该得到8.00.2039。任何版本号都小于此值,您应该安装SP4。

答案 2 :(得分:0)

fldField = '%YYY%'怎么样?

答案 3 :(得分:0)

它在我的SQL 2005安装上按预期工作。如果它适用于其他机器,听起来你有一个环境差异。尝试比较SQL Server Management Studio中的连接属性,以获得有效的连接和无法查看是否可以找出差异的连接。

答案 4 :(得分:0)

我是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中,等分解决的速度比想要快。

答案 5 :(得分:0)

如果在未指定任何搜索条件的情况下使用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) + ']%'

答案 6 :(得分:0)

多么可爱的小虫。我想我知道原因。如果我是对的,那么你将得到你期望的结果:

SELECT
  CASE
    WHEN fldField like 'YYY       '  -- 7 spaces
    THEN 'OTH'
    ELSE 'XXX'
  END as newField
from tmpTable

错误是varchar(10)的行为类似于char(10)。至于它为什么没有,你需要理解一个旧的琐事问题,即两个没有元字符的字符串是如何=但彼此不相似。

问题是char(10)在内部被认为是空间填充的。 like运算符忽略这些空格。 =运算符应该是chars的情况。内存告诉我Oracle通常会忽略字符串的空格。 Postgres用铸造做了一些技巧。我没有使用SQL * Server,所以我无法告诉你它是如何做到的。

答案 7 :(得分:0)

通过向表达式添加(%),它可以正常工作。

SELECT
CASE 
    WHEN fldField like '%YYY%' THEN 'OTH' 
    ELSE 'XXX' END AS newField
END

答案 8 :(得分:-1)

您没有指定要选择的内容并检查CASE ...

SELECT  CASE fldField WHEN 'YYY' 
THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable