在CASE表达式SQL Server 2012+中调用标量函数

时间:2016-02-16 08:48:18

标签: sql sql-server tsql

我试图在T-SQL中模拟PL / SQL DECODE()函数:

CREATE FUNCTION [dbo].[fnDecode]
(
    @condition     AS BIT,
    @trueVal       AS VARCHAR(2000),
    @falseVal      AS VARCHAR(2000)
)
RETURNS VARCHAR(2000)
WITH EXEC AS CALLER AS
BEGIN
    RETURN CASE @condition
                WHEN 1 THEN @trueVal
                ELSE @falseVal
           END
END
GO

尝试移植到T-SQL的PL / SQL片段是:

CASE pcr.person_type
WHEN 'N'
THEN
      npcr.first_name
   || DECODE (npcr.middle_name,
              NULL, '',
              ' ' || npcr.middle_name)
   || ' '
   || npcr.last_name
WHEN 'L'
THEN
   lpcr.name
END

我想在CASE语句中调用上面定义的标量函数,如下所示:

CASE pcr.person_type
  WHEN 'N' THEN npcr.first_name
      + dbo.fnDecode(npcr.middle_name IS NULL, '', ' ' + npcr.middle_name)
      + ' '
      + npcr.last_name
  WHEN 'L' THEN lpcr.name
END

我无法将fnDecode()函数的结果存储到变量中,因为行来自某些连接表(并且在我移植的查询中有多个fnDecode()调用)

我们正在使用SQL Server 2012和2014。

2 个答案:

答案 0 :(得分:2)

移植程序方法"因为它是" 根本不是一个好习惯。这不是PHP,C#甚至是PL / SQL。此外,在描述的情况下,您甚至不需要任何函数调用。 NULL和上面提到的场景中的空字符串处理非常简单,不需要任何程序方法。

有函数NULLIFISNULLCOALESCECASE语句。您需要的一切就是检查某些内容是true还是falsenull

每行的标量UDF调用可能(并且会)导致严重性能问题。

检查出来:

CASE pcr.person_type
  WHEN 'N' THEN npcr.first_name
      + IsNull(' ' + npcr.middle_name, '')
      + ' '
      + npcr.last_name
  WHEN 'L' THEN lpcr.name
END

即使你已经禁用了ANSI_NULLS和CONCAT_NULL_YIELD_NULL选项而且没有'希望给服务器任何错误的机会,你可以使用case,这种方法比调用函数要好得多:

CASE pcr.person_type
  WHEN 'N' THEN npcr.first_name
      + case when npcr.middle_name is NULL then '' else ' ' + npcr.middle_name end
      + ' '
      + npcr.last_name
  WHEN 'L' THEN lpcr.name
END

如果允许空标记,则此代码可以正常工作(设置常规空选项):

CASE pcr.person_type
  WHEN 'N' THEN npcr.first_name
      + IsNull(' ' + NullIf(npcr.middle_name, ''), '')
      + IsNull(' ' + NullIf(npcr.last_name, ''), '')
  WHEN 'L' THEN lpcr.name
END

答案 1 :(得分:1)

是的,从CASE表达式(以及许多其他地方)调用标量函数当然是可能的。

您遇到的问题与第一个参数有关。 BIT是一种数字数据类型。不是boolean,事实上,SQL Server在T-SQL中没有公开的boolean数据类型。因此,您不能将fDecode函数的第一个参数设置为布尔值,也不能在预期接受npcr.middle_name = NULL的位置传递评估谓词的结果,例如bit

this 之类的东西应该执行:

CASE pcr.person_type
  WHEN 'N' THEN npcr.first_name
      + dbo.fnDecode(CASE WHEN npcr.middle_name = NULL THEN 1 ELSE 0 END, '', ' ' + npcr.middle_name)
      + ' '
      + npcr.last_name
  WHEN 'L' THEN lpcr.name
END

(虽然你可能还需要插入一个显式的演员表)

但这使得治疗看起来比诅咒更糟糕。

在任何情况下,您都可以使用内置的IIF函数而不是fDecode。因为它是内置的,所以它不会遵循您必须遵循的相同规则,事实上它的第一个参数是一个布尔表达式。