Скорее всего, основная причина в том, что Табличные Функции возвращают Результирующий Набор, точно так же как Таблицы и Представления. Это означает , что они могут быть использованы в FROM
пункте ( в том числе JOIN
с и APPLY
с, и т.д.) из SELECT
, UPDATE
и DELETE
запросов. Однако вы не можете использовать Scalar UDF в любом из этих контекстов.
Во-вторых, вы также можете EXECUTE
скалярной UDF. Этот синтаксис очень удобен, если для входных параметров указаны значения по умолчанию. Возьмите следующий UDF, например:
CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
RETURN @Param1 + @Param2;
END;
Если вы хотите обработать любой из входных параметров как «необязательный», вам все равно нужно передать DEFAULT
ключевое слово при вызове его как функцию, поскольку сигнатура исправлена:
DECLARE @Bob1 INT;
SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);
SELECT @Bob1;
-- Returns: 102
С другой стороны, если вы EXECUTE
функция, то вы можете рассматривать любые параметры со значением по умолчанию как необязательные, так же, как вы можете использовать хранимые процедуры. Вы можете передать первые n параметров без указания имен параметров:
DECLARE @Bob2 INT;
EXEC @Bob2 = dbo.OptionalParameterTest 50;
SELECT @Bob2;
-- Returns: 52
Вы даже можете пропустить первый параметр, указав имена параметров, как и в случае с хранимыми процедурами:
DECLARE @Bob3 INT;
EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;
SELECT @Bob3;
-- Returns: 51
ОБНОВИТЬ
Почему вы можете использовать EXEC
синтаксис для вызова скалярной UDF, как хранимой процедуры? Иногда есть UDF, которые замечательно иметь в качестве UDF, так как они могут быть добавлены в запрос и работать с набором возвращаемых строк, тогда как если бы код находился в хранимой процедуре, его нужно было бы поместить в курсор, чтобы перебрать набор строк. Но иногда бывают случаи, когда вы хотите вызвать эту функцию для одного значения, возможно, из другого UDF. Вызов UDF для одного значения может быть выполнен как:
SELECT dbo.UDF('some value');
в этом случае вы получаете возвращаемое значение в наборе результатов (набор результатов не будет работать). Или это можно сделать следующим образом:
DECLARE @Dummy INT;
SET @Dummy = dbo.UDF('some value');
в этом случае вам нужно объявить @Dummy
переменную;
ОДНАКО, используя EXEC
синтаксис, вы можете избежать обеих этих неприятностей:
EXEC dbo.UDF 'some value';
ТАКЖЕ, скалярные UDF имеют свои планы выполнения в кэше. Это означает, что можно столкнуться с проблемами отслеживания параметров, если в UDF есть запросы с планами выполнения. Для сценариев, где возможно использование EXEC
синтаксиса, можно также использовать WITH RECOMPILE
опцию, чтобы игнорировать скомпилированное значение плана для этого выполнения . Например:
НАСТРОИТЬ:
GO
CREATE FUNCTION dbo.TestUDF (@Something INT)
RETURNS INT
AS
BEGIN
DECLARE @Ret INT;
SELECT @Ret = COUNT(*)
FROM sys.indexes si
WHERE si.[index_id] = @Something;
RETURN @Ret;
END;
GO
ТЕСТОВОЕ ЗАДАНИЕ:
DECLARE @Val INT;
SET @Val = dbo.TestUDF(1);
SELECT @Val;
EXEC @Val = dbo.TestUDF 0 -- uses compiled value of (1)
SELECT @Val;
EXEC @Val = dbo.TestUDF 0 WITH RECOMPILE; -- uses compiled value of (0)
SELECT @Val;
EXEC @Val = dbo.TestUDF 3 -- uses compiled value of (1)
SELECT @Val;