就像在 CASE 语句中没有按预期进行评估一样

Posted

技术标签:

【中文标题】就像在 CASE 语句中没有按预期进行评估一样【英文标题】:Like in CASE statement not evaluating as expected 【发布时间】:2008-09-22 19:17:22 【问题描述】:

鉴于此数据:

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 其他

什么情况会导致 SQL server 2000 找不到“YYY”?并将以下内容作为结果集返回: XXX XXX XXX XXX XXX

问题出在“YYY”之类的问题上,我找到了其他方法来编写它以使其工作,但我想知道为什么这种确切的方法不起作用。另一个困难是它适用于我的大多数 SQL Server 2000 环境。我需要找出它们之间有什么不同导致这种情况。感谢您的帮助。

【问题讨论】:

【参考方案1】:

检查您的服务包。将我的 SQL 2000 机器升级到 SP4 后,我现在得到了适合您情况的正确值。

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

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

【讨论】:

您说的完全正确。我刚刚在 Mocrosoft 的网站support.microsoft.com/kb/279293/en-us 上找到了关于几乎相同问题的错误记录。我确认给我带来问题的版本没有打补丁。 SP1 解决了这个问题。【参考方案2】:

我在 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 如何在同一行中有两个不同的值?我已经请了这里办公室的其他人进行快速测试。对我来说似乎是一个错误。

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

我是 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】:

当您使用 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】:

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

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

错误是 varchar(10) 的行为类似于 char(10) 应该的行为。至于为什么不这样,你需要理解一个古老的琐事问题,即两个没有元字符的字符串如何可以 = 但不能互相喜欢。

问题是 char(10) 应该在内部填充空格。 like 运算符确实 not 忽略这些空格。 = 运算符应该在字符的情况下。内存告诉我,Oracle 通常会忽略字符串的空格。 Postgres 做了一些转换技巧。我没有使用过 SQL*Server,所以我不能告诉你它是怎么做的。

【讨论】:

【参考方案7】:

fldField = '%YYY%'怎么样?

【讨论】:

正确,添加通配符使其工作。我试图找出为什么它不像书面的那样工作。它应该。像 'YYY' 应该在找到值 'YYY' 时评估为真。【参考方案8】:

通过将 (%) 添加到表达式中,它会正常工作。

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

【讨论】:

【参考方案9】:

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

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

【讨论】:

以上是关于就像在 CASE 语句中没有按预期进行评估一样的主要内容,如果未能解决你的问题,请参考以下文章

如何在选择案例语句中实现枚举

Go——处理用户连接超时

SQL Server CASE 表达式未按预期计算

switch case 语句中的分号

LISTAGG 被评估并在无法访问的 case 语句中失败

我的代码就像在一个while循环中一样,即使它不是