Пользовательская функция SQL Server, принимающая аргументы любого типа, например ISNULL

Мне нужно создать пользовательскую функцию, которая будет работать аналогично системной функции ISNULL в том отношении, что она будет принимать аргументы любого типа и возвращать значение того же типа. Как это делается?

Использование SQL_VARIANT в качестве типа данных не будет работать, поскольку значения SQL_VARIANT требуют явного приведения. ISNULL неявно выполняет преобразования типов данных.

Как объявить универсальные типы, не требующие явного приведения?

Позвольте мне внести ясность. Я не собираюсь копировать функциональность функции ISNULL. Я использовал функцию ISNULL как образец функции, которая принимает два аргумента любого типа данных, поддерживаемого SQL Server, и возвращает значение того же типа данных, что и аргументы.

Существуют и другие функции SQL Server, которые реализуют тот же шаблон: принимают аргументы, тип данных которых не объявлен явно, и возвращают значение какого-либо другого типа данных, который также не объявлен явно при определении функции. Примеры: NULLIF, CAST, CONVERT.

Мне интересно, как этот шаблон может быть выполнен, потому что любой UDF требует явного определения аргументов и типов данных возвращаемого значения.


person Ramzay    schedule 07.10.2015    source источник
comment
Каким должно быть значение замены для каждого типа? Заменить NULL-строку пустой строкой довольно очевидно, но что такое незначащее значение для datetime? Действительно ли Zero не является значением числового типа? Чего вы хотите достичь?   -  person Shnugo    schedule 07.10.2015
comment
T-SQL не имеет дженериков, а типы возвращаемых функций, определяемые пользователем, являются статическими (и обязательными), поэтому то, о чем вы буквально просите, невозможно. Есть несколько вещей, о которых я могу думать, которые могли бы достичь того, чего вы хотите (например, хранимая процедура, которая дает таблицу или динамический SQL), но также и веские причины, по которым вы не хотели бы использовать их в производственном коде. Поскольку ISNULL уже существует и прекрасно работает, что именно вам нужно, похожее на ISNULL, и для чего?   -  person Jeroen Mostert    schedule 07.10.2015
comment
Shnugo, суть в том, чтобы иметь функцию, не зависящую от типа аргумента и способную принимать любой, как это делают такие функции, как ISNULL или NULLIF. Дело не в том, чтобы реализовать другую версию ISNULL, а в том, чтобы иметь возможность создать новую функцию, которая могла бы обрабатывать аргументы любого времени и, что более важно, возвращать значение того же типа, что и аргументы.   -  person Ramzay    schedule 03.01.2016
comment
Jeroen Mostert, я озадачен тем, что непонятно в моем исходном вопросе. Я четко заявил, что мне не нужно создавать еще одну функцию ISNULL. Я объясняю, что сходство, которое я ищу, строго по образцу.   -  person Ramzay    schedule 03.01.2016


Ответы (1)


Я только что ответил на вопрос, который как-то связан: 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)
person Shnugo    schedule 08.10.2015
comment
Это действительно увлекательно и очень познавательно. Я ценю, что вы поделились этой информацией. Уверен, что найду ему достойное применение. Однако это не приближает меня к ответу на мой вопрос: как SQL Server реализует такие функции, как ISNULL, CONVERT, CAST, NULLIF, без явного определения параметров и типов данных возвращаемых значений? - person Ramzay; 03.01.2016