将case语句与stuff结合使用

时间:2018-01-26 12:50:56

标签: sql sql-server tsql

我的部分查询如下:

  contNumber = STUFF((SELECT ', ' + RTRIM(LTRIM(t.contNumber))
                FROM dbContactNumbers t
                where d.contid = t.contid
                FOR XML PATH ('')), 1, 1, ''),

我必须使用它,因为我有一对多的关系,这是一种快速简便的方法,可以在一行中返回相关值。

我想基于这个字段做一个case语句,将NULL等于44,但是当我在查询中的任何地方尝试使用普通的case语句时,我会遇到语法错误,如下所示:

case contnumber when '44' then NULL else contnumber,

Msg 102, Level 15, State 1, Line 17
Incorrect syntax near ','.
Msg 156, Level 15, State 1, Line 21
Incorrect syntax near the keyword 'FOR'.

执行此case语句的正确语法是什么,假设它甚至可能?我正在使用SQL Server 2008 R2。

2 个答案:

答案 0 :(得分:2)

你可能想要:

contNumber = CASE WHEN STUFF((SELECT ', ' + RTRIM(LTRIM(t.contNumber))
                FROM dbContactNumbers t
                where d.contid = t.contid
                FOR XML PATH ('')), 1, 1, '') = ' 44' THEN NULL
             ELSE STUFF((SELECT ', ' + RTRIM(LTRIM(t.contNumber))
                FROM dbContactNumbers t
                where d.contid = t.contid
                FOR XML PATH ('')), 1, 1, '')
             END

另一种方法是用子查询/ CTE包装它:

WITH cte AS (
SELECT   contNumber = STUFF((SELECT ', ' + RTRIM(LTRIM(t.contNumber))
                FROM dbContactNumbers t
                where d.contid = t.contid
                FOR XML PATH ('')), 1, 1, ''),
-- ...
)
SELECT case contnumber when ' 44' then NULL else contnumber, ...
FROM cte

最明确的解决方案是使用NULLIF

contNumber = NULLIF(STUFF((SELECT ', ' + RTRIM(LTRIM(t.contNumber))
                FROM dbContactNumbers t
                where d.contid = t.contid
                FOR XML PATH ('')), 1, 1, ''), ' 44')

答案 1 :(得分:1)

lad2025的答案很棒(尤其是关于NULLIF(来自我身边的+1),只是一个提示:

您不能像使用计算列一样使用命名变量。是的,您可以重复表达,但在更复杂的情况下,这很难阅读。

但有CROSS APPLY

这允许您创建基于行的派生表。使用如下结构,您可以将计算(甚至许多列)转换为派生的列集,您可以像命名变量一样使用它。

以下示例毫无意义,但显示了原则:

SELECT object_id 
      ,[name]
      ,namedVariable
FROM sys.objects
CROSS APPLY(SELECT 'Anything') AS A(namedVariable)