User-defined functions: reuse a calculation or a set

Some rules appear over and over again within queries: calculate an amount, get a label, or select a set using a parameter. A function gives them a name and allows them to be used as part of another query.

Scalar functions, which return a value, and table-valued functions, which return rows, are common in SQL Server.

Scalar function

A scalar function returns a single value for each invocation. In the following calculation, ROUND(expresión, 2) rounds the amount to two decimal places before returning it.

CREATE OR ALTER FUNCTION dbo.ufn_ImportePartida
(
    @Cantidad INT,
    @PrecioUnitario DECIMAL(12, 2),
    @Descuento DECIMAL(5, 2)
)
RETURNS DECIMAL(14, 2)
AS
BEGIN
    RETURN ROUND(
        @Cantidad * @PrecioUnitario * (1 - @Descuento / 100.0),
        2
    );
END;
GO

It is invoked with the schema and the function name:

SELECT
    d.IdDetallePedido,
    dbo.ufn_ImportePartida(
        d.Cantidad,
        d.PrecioUnitario,
        d.Descuento
    ) AS Importe
FROM dbo.DetallePedido AS d;

The function makes a shared rule visible, but we should not assume that wrapping an expression always improves performance. We measure its cost when it is evaluated over many rows.

Inline table-valued function

CREATE OR ALTER FUNCTION dbo.ufn_ProductosPorCategoria
(
    @IdCategoria SMALLINT
)
RETURNS TABLE
AS
RETURN
(
    SELECT
        p.IdProducto,
        p.Nombre,
        p.Precio,
        p.Existencia
    FROM dbo.Producto AS p
    WHERE p.IdCategoria = @IdCategoria
      AND p.Activo = 1
);
GO

The function is used in FROM as a parameterized table:

SELECT
    p.IdProducto,
    p.Nombre,
    p.Precio
FROM dbo.ufn_ProductosPorCategoria(2) AS p
WHERE p.Existencia > 0
ORDER BY p.Nombre;

An inline table-valued function defines its result with one query. It usually integrates into the execution plan better than a function with several statements and an internal table variable. The optimizer, the component that compares execution strategies, can consider the consuming query together with that definition.

Difference vs. a view

A view exposes a query without parameters. A table-valued function accepts values ​​and returns an array that can be joined, filtered, or grouped.

If we need multiple result sets, modifications, transaction control, or an operation with broader effects, a stored procedure often better represents the intent.

Important limits

Functions should behave like reusable expressions. A side effect is a change outside the returned value, such as modifying a table. Functions cannot freely perform those effects, return several independent sets, or control transactions like a procedure.

It is also a good idea to avoid hiding expensive queries behind a simple name. Just because the call occupies a line does not mean that its execution is cheap.

What should be checked

We review input and output types, treatment of NULL, decimal precision, determinism, and cost in the plan. A function is deterministic when the same inputs and state produce the same result. A scalar function may conceptually run for each row; recent versions can optimize some cases, but not every function meets the required conditions.

When the rule is brief and only used once, a direct expression may be clearer. We create a feature when the name, reuse, or contract justifies the additional object.