SQL Server用户定义函数接受任何类型的参数,如ISNULL

时间:2015-10-07 18:24:54

标签: sql-server generics types user-defined-functions isnull

我需要创建一个用户定义的函数,它的操作类似于ISNULL系统函数,因为它接受任何类型的参数并返回相同类型的值。 这是怎么做到的?

使用SQL_VARIANT作为数据类型不起作用,因为SQL_VARIANT值需要显式转换。 ISNULL隐式执行数据类型转换。

如何声明不需要显式转换的泛型类型?

让我说清楚。我不打算复制ISNULL功能的功能。我使用ISNULL函数作为函数的模式,它接受SQL Server支持的任何数据类型的两个参数,并返回与参数相同的数据类型的值。

还有其他SQL Server函数实现相同的模式:接受未显式声明数据类型的参数,并返回某些其他数据类型的值,这也未在函数定义中显式声明。示例包括:NULLIF,CAST,CONVERT。

我想知道如何实现这种模式,因为任何UDF都需要显式定义参数和返回值数据类型。

1 个答案:

答案 0 :(得分:0)

我刚回答了一个与某种程度相关的问题:https://stackoverflow.com/a/32985478/5089204

没有安全的方法来处理空值。在大多数情况下,ISNULL非常好,但如果你没有隐式可转换类型的两个参数,那么它就不会编译。

看看如何用XML处理它。只需将其粘贴到一个空的查询窗口中并执行:

--The NULL-element is not there at all
SELECT 'text' AS filled
      ,'' AS empty
      ,NULL AS NotThere
FOR XML PATH('row');   

--The NULL-element is rendered using "nil"
SELECT 'text' AS filled
      ,'' AS empty
      ,NULL AS NotThere
FOR XML PATH('row'),ELEMENTS XSINIL    

--Look at this: Both columns are called "TheName". They are implicitly concatenated
SELECT 'a' AS TheName
      ,'b' AS TheName
FOR XML PATH('row')

--That leads to: Concatenate nothing with an empty string will at least return the empty string.
--this is other/better than ISNULL, because it will work with any type...
SELECT NULL AS TheName
      ,'' AS TheName
FOR XML PATH('row')

--now an example with table data
DECLARE @tbl TABLE(int1 INT, int2 INT);
INSERT INTO @tbl VALUES(NULL,1); --first value is null

--int1 is swallowed
SELECT *
FROM @tbl
FOR XML PATH('row')

--both elements are there
SELECT int1, '' AS int1 --ISNULL(int1,'') would not compile here...
      ,int2, '' AS int2
FROM @tbl
FOR XML PATH('row')

--This is the result of the last example: Look what happens to the empty int element, its Zero! 
--This is the way this is handled in XML conversions. Try it with other types (like 'date' [result is 1900-01-01] or any other type)...
DECLARE @a XML='<row><int1></int1><int2>1</int2></row>';
SELECT a.b.value('int1[1]','int') AS int1
      ,a.b.value('int2[1]','int') AS int2
FROM @a.nodes('/row') a(b)