Criar funções definidas pelo utilizador
As funções definidas pelo usuário (UDF) são semelhantes aos procedimentos armazenados, pois são armazenadas separadamente das tabelas no banco de dados. Essas funções aceitam parâmetros, executam uma ação e, em seguida, retornam o resultado da ação como um único valor (escalar) ou um conjunto de resultados (valor de tabela). Em seguida, você pode usar a função no lugar de uma tabela ao escrever uma instrução SELECT. As funções definidas pelo usuário destinam-se a executar cálculos e usar esse resultado em outra instrução. Considerando que os procedimentos armazenados podem encapsular a função e a instrução e até mesmo modificar dados dentro do banco de dados.
Analisaremos três tipos de funções definidas pelo usuário. Para obter mais detalhes sobre as diferentes funções, consulte a documentação de referência do T-SQL.
Funções com valor de tabela integradas
As funções com valor de tabela embutido (TVF) são a função mais simples criada com base em uma instrução SELECT e são a escolha preferida para desempenho.
No exemplo a seguir, uma função com valor de tabela é criada com um parâmetro de entrada para preço unitário.
CREATE FUNCTION SalesLT.ProductsListPrice(@cost money)
RETURNS TABLE
AS
RETURN
SELECT ProductID, Name, ListPrice
FROM SalesLT.Product
WHERE ListPrice > @cost;
Quando a função com valor de tabela é executada com um valor para o parâmetro, todos os produtos com um preço unitário superior a esse valor serão retornados.
O código a seguir usa a função com valor de tabela no lugar de uma tabela.
SELECT Name, ListPrice
FROM SalesLT.ProductsListPrice(500);
Funções valorizadas por tabelas de múltiplas instruções
Ao contrário do TVF embutido, uma função com valor de tabela de várias instruções (MSTVF) pode ter mais de uma instrução e tem requisitos de sintaxe diferentes.
Observe como no código a seguir, usamos um BEGIN/END além de 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;
Uma vez criado, você faz referência ao MSTVF no lugar de uma tabela, assim como com a função embutida anterior acima. Você também pode fazer referência à saída na cláusula FROM e juntá-la a outras tabelas.
SELECT *
FROM Sales.mstvf_OrderStatus();
Considerações sobre desempenho
O Otimizador de Consulta não consegue estimar quantas linhas serão retornadas por uma função valorizada por tabela de múltiplas instruções, mas consegue com a função valorizada por tabela em linha. Portanto, use o TVF em linha quando possível para um melhor desempenho. Se você não precisa unir o MSTVF com outras tabelas e/ou sabe que o resultado será apenas algumas linhas, o impacto no desempenho não é tão preocupante. Se você espera um grande conjunto de resultados e precisa se unir a outras tabelas, considere usar uma tabela temporária para armazenar os resultados e, em seguida, ingressar na tabela temporária.
No SQL Server versões 2017 e superiores, a Microsoft introduziu recursos para processamento inteligente de consultas para melhorar o desempenho do MSTVF. Veja mais detalhes sobre os recursos de Processamento Inteligente de Consultas na Documentação de Referência do T-SQL.
Funções escalares definidas pelo usuário
Uma função escalar definida pelo usuário retorna apenas um valor, ao contrário das funções com valor de tabela e, portanto, é frequentemente usada para instruções simples e frequentes.
Aqui está um exemplo para obter o preço de tabela de produtos para um produto específico em um determinado dia:
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
Para esta função, ambos os parâmetros devem ser fornecidos para obter o valor. Dependendo da função, você pode listar a função na instrução SELECT em uma consulta mais complexa.
SELECT dbo.ufn_GetProductListPrice (707, '2011-05-31')
Vincular função a objetos referenciados
SCHEMABINDING é opcional ao criar a função. Quando você especifica SCHEMABINDING, ele vincula a função aos objetos referenciados e, em seguida, os objetos não podem ser modificados sem também modificar a função. A função deve primeiro ser modificada ou descartada para remover dependências antes de modificar o objeto.
SCHEMABINDING é removido se ocorrer qualquer uma das seguintes situações:
- A função é descartada
- A função é modificada com a instrução ALTER sem especificar SCHEMABINDING