Создание функций, определяемых пользователем
Определяемые пользователем функции (UDF) похожи на хранимые процедуры, которые хранятся отдельно от таблиц в базе данных. Эти функции принимают параметры, выполняют действие, а затем возвращают результат действия в виде одного (скалярного) значения или результирующий набор (табличное значение). Затем можно использовать функцию вместо таблицы при написании инструкции SELECT. Определяемые пользователем функции предназначены для выполнения вычислений и использования этого результата в другой инструкции. В то время как хранимые процедуры могут инкапсулировать функцию и инструкцию, а также изменять данные в базе данных.
Мы рассмотрим три типа определяемых пользователем функций. Дополнительные сведения о различных функциях см. в справочной документации по T-SQL.
Функции с табличным значением типа inline
Встроенные табличные функции (TVF) — это простейшая функция, созданная на основе инструкции SELECT, и это предпочтительный выбор для производительности.
В следующем примере функция с табличным значением создается с входным параметром для unitprice.
CREATE FUNCTION SalesLT.ProductsListPrice(@cost money)
RETURNS TABLE
AS
RETURN
SELECT ProductID, Name, ListPrice
FROM SalesLT.Product
WHERE ListPrice > @cost;
Когда функция с табличным значением запускается со значением параметра, то будут возвращены все продукты с ценой единицы больше, чем это значение.
Следующий код использует табличную функцию вместо таблицы.
SELECT Name, ListPrice
FROM SalesLT.ProductsListPrice(500);
Функции с табличным значением с несколькими операторами
В отличие от встроенного TVF, многооператорная функция с табличным значением (MSTVF) может содержать несколько операторов и имеет разные требования к синтаксису.
Обратите внимание, что в следующем коде мы используем begin/END в дополнение к RETURN:
CREATE FUNCTION Sales.mstvf_OrderStatus ()
RETURNS
@Results TABLE
( CustomerID int, OrderDate datetime )
AS
BEGIN
INSERT INTO @Results
SELECT SC.CustomerID, OrderDate
FROM Sales.Customer AS SC
INNER JOIN Sales.SalesOrderHeader AS SOH
ON SC.CustomerID = SOH.CustomerID
WHERE Status >= 5
RETURN;
END;
После создания ссылайтесь на MSTVF вместо таблицы, так же, как и на предыдущую встроенную функцию, упомянутую выше. Вы также можете ссылаться на выходные данные в предложении FROM и присоединить его к другим таблицам.
SELECT *
FROM Sales.mstvf_OrderStatus();
Вопросы, связанные с производительностью
Оптимизатор запросов не может оценить количество строк, которое будет возвращено многооператорной функцией с табличным значением, но может сделать это для встроенной функции с табличным значением. Поэтому используйте встроенный TVF, если это возможно, для повышения производительности. Если вам не нужно присоединять MSTVF к другим таблицам и/или вы знаете, что результат будет содержать только несколько строк, то влияние на производительность будет менее значительным. Если ожидается большой результирующий набор и требуется присоединиться к другим таблицам, вместо этого рекомендуется использовать временную таблицу для хранения результатов, а затем присоединиться к временной таблице.
В SQL Server версии 2017 и более поздних версиях корпорация Майкрософт представила функции интеллектуальной обработки запросов для повышения производительности MSTVF. Дополнительные сведения о функциях интеллектуальной обработки запросов см. в справочной документации по T-SQL.
Скалярные пользовательские функции
Скалярная определяемая пользователем функция возвращает только одно значение в отличие от табличных функций, поэтому часто используется для простых, частых инструкций.
Ниже приведен пример получения каталожной цены для конкретного продукта в определенный день.
CREATE FUNCTION dbo.ufn_GetProductListPrice
(@ProductID [int], @OrderDate [datetime])
RETURNS [money]
AS
BEGIN
DECLARE @ListPrice money;
SELECT @ListPrice = plph.[ListPrice]
FROM [Production].[Product] p
INNER JOIN [Production].[ProductListPriceHistory] plph
ON p.[ProductID] = plph.[ProductID]
AND p.[ProductID] = @ProductID
AND StartDate = @OrderDate
RETURN @ListPrice;
END;
GO
Для этой функции необходимо указать оба параметра, чтобы получить это значение. В зависимости от функции можно перечислить функцию в инструкции SELECT в более сложном запросе.
SELECT dbo.ufn_GetProductListPrice (707, '2011-05-31')
Привязка функции к объектам, на которые ссылается ссылка
SCHEMABINDING опционален при создании функции. При указании SCHEMABINDING функция привязывается к объектам, на которые ссылается ссылка, а затем объекты нельзя изменять, не изменяя функцию. Перед изменением объекта функция должна быть изменена или удалена, чтобы удалить зависимости.
SCHEMABINDING удаляется при возникновении любого из следующих действий:
- Функция удаляется
- Функция изменяется с помощью инструкции ALTER без указания SCHEMABINDING