Sei sulla pagina 1di 11

Directrices para el diseño de funciones definidas por el

usuario
http://msdn.microsoft.com/es-es/library/ms187440.aspx

Una función definida por el usuario se almacena como un objeto de base de datos que proporciona código reutilizable y
se puede utilizar de las siguientes maneras:

 En instrucciones Transact-SQL como SELECT


 En las aplicaciones que llaman a la función
 En la definición de otra función definida por el usuario
 Para parametrizar una vista o mejorar la funcionalidad de una vista indizada
 Para definir una columna en una tabla
 Para definir una restricción CHECK en una columna
 Para reemplazar un procedimiento almacenado

Elegir un tipo de función

Al diseñar una función definida por el usuario, primero es preciso determinar el tipo de función que mejor se ajuste a sus
necesidades. Así pues, es necesario determinar si la función:

 Devolverá un valor escalar (un solo valor)


 Devolverá una tabla (varias filas)
 Realizará un cálculo complejo
 Si tendrá acceso principalmente a los datos de SQL Server

Las funciones definidas por el usuario escritas en Transact-SQL o .NET Framework pueden devolver valores escalares y de
tabla.

Propiedades de las funciones

Son varias las propiedades de las funciones definidas por el usuario que determinan la capacidad de SQL Server Database
Engine (Motor de base de datos de SQL Server) para indizar los resultados de la función, ya sea mediante índices en
columnas calculadas que llaman a la función o mediante vistas indizadas que hacen referencia a la función. Estas
propiedades también se aplican a los métodos de tipos definidos por el usuario para CLR.

Determinismo

Las funciones deterministas devuelven el mismo resultado cada vez que se llaman con un conjunto específico de valores
de entrada y cuando el estado de la base de datos es el mismo. Las funciones no deterministas pueden devolver
resultados diferentes cada vez que se llaman con un conjunto específico de valores de entrada aunque el estado de la
base de datos a la que tienen acceso permanezca sin cambios.

Motor de base de datos analiza automáticamente el cuerpo de las funciones Transact-SQL y evalúa si la función es
determinista. Por ejemplo, si la función llama a otras funciones que no son deterministas o si la función llama a
procedimientos almacenados extendidos, entonces, Motor de base de datos marca la función como no determinista. Para

1
las funciones CLR (Common Language Runtime), Motor de base de datos confía en el autor de la función para marcar o
no la función como determinista mediante el atributo personalizado SqlFunction.

Precisión

Una función definida por el usuario se considera precisa si en ella no interviene ninguna operación de coma flotante.

Motor de base de datos analiza automáticamente el cuerpo de las funciones Transact-SQL y evalúa si la función es precisa.
Para las funciones CLR, Motor de base de datos confía en el autor de la función para marcar o no la función como precisa
mediante el atributo personalizado SqlFunction.

Acceso a datos

Esta propiedad indica si la función tiene acceso al servidor de la base de datos local mediante un proveedor administrado
en curso de SQL Server. Para obtener más información, vea Acceso a datos de objetos de base de datos de CLR.

Motor de base de datos analiza automáticamente el cuerpo de las funciones Transact-SQL y evalúa si la función realiza el
acceso a datos. Para las funciones CLR, Motor de base de datos confía en el autor de la función para indicar las
características del acceso a los datos mediante el atributo personalizado SqlFunction. Motor de base de datos fuerza el
uso de esta propiedad en tiempo de ejecución. Si la función indica que DataAccess = None, pero se realiza el acceso a los
datos, la función no será correcta en tiempo de ejecución.

Acceso a datos del sistema

Esta propiedad indica si la función tiene acceso a los metadatos del sistema en el servidor de la base de datos local
mediante un proveedor administrado en curso de SQL Server.

Motor de base de datos analiza automáticamente el cuerpo de las funciones Transact-SQL y evalúa si la función realiza el
acceso a datos del sistema. Para las funciones CLR, Motor de base de datos confía en el autor de la función para indicar las
características del acceso a los datos del sistema mediante el atributo personalizado SqlFunction. Motor de base de datos
fuerza el uso de esta propiedad en tiempo de ejecución. Si la función indica que SystemDataAccess = None, pero se
realiza el acceso a los datos del sistema, la función no será correcta en tiempo de ejecución.

IsSystemVerified

Esta propiedad indica si Motor de base de datos puede comprobar las propiedades de determinismo y precisión de la
función. Esta propiedad es verdadera para las funciones Transact-SQL siempre que no llamen a ninguna función marcada
como IsSystemVerified = false. La propiedad es falsa para las funciones CLR.

Motor de base de datos deriva automáticamente la propiedad IsSystemVerified para las funciones. Para las funciones
Transact-SQL, si tienen acceso a cualquier función marcada como IsSystemVerified = false, la propia función se marca
como IsSystemVerified = false.

Para obtener más información acerca de las columnas calculadas indizadas y las vistas indizadas, vea Crear índices en
columnas calculadas y Crear vistas indizadas.

2
Funciones definidas por el usuario con valores de
tabla
http://msdn.microsoft.com/es-es/library/ms191165.aspx

Las funciones definidas por el usuario que devuelven un tipo de datos table pueden ser unas eficaces alternativas a las
vistas. Esas funciones se conocen como funciones con valores de tabla. Una función definida por el usuario con valores de
tabla se puede usar donde se permiten las expresiones de vista o de tabla en las consultas Transact-SQL. Mientras que las
vistas se limitan a una única instrucción SELECT, las funciones definidas por el usuario pueden contener instrucciones
adicionales que permiten una lógica más eficaz que en las vistas.

Una función definida por el usuario con valores de tabla también puede reemplazar procedimientos almacenados que
devuelven un solo conjunto de resultados. En la cláusula FROM de una instrucción Transact-SQL es posible hacer
referencia a la tabla que devuelve una función definida por el usuario, pero esto no es posible con los procedimientos
almacenados que devuelven conjuntos de resultados.

Componentes de una función definida por el usuario con valores de tabla

En una función definida por el usuario con valores de tabla:

 La cláusula RETURNS define el nombre de una variable de retorno local para la tabla devuelta por la función. La
cláusula RETURNS también define el formato de la tabla. El nombre de una variable de retorno local tiene un
ámbito local dentro de la función.
 Las instrucciones Transact-SQL del cuerpo de la función generan e insertan filas en la variable de retorno definida
por la cláusula RETURNS.
 Al ejecutar una instrucción RETURN, las filas insertadas en la variable se devuelven desde la función en formato
tabular. La instrucción RETURN no puede tener un argumento.

Ninguna instrucción Transact-SQL de una función con valores de tabla puede devolver un conjunto de resultados
directamente a un usuario. La única información que la función puede devolver al usuario es el tipo de datos table devuelto
por la función.

Nota
La opción de tabla text in row se define automáticamente en 256 para una tabla devuelta por una función
definida por el usuario. Esto no puede modificarse. Las instrucciones READTEXT, WRITETEXT y
UPDATETEXT no pueden utilizarse para leer o escribir partes de las columnas text, ntext e image de la tabla.
Para obtener más información, vea Datos consecutivos.

Ejemplo

En el siguiente ejemplo se crea la función dbo.ufnGetContactInformation y se muestran los componentes de la función


con valores de tabla. En esta función, el nombre de la variable de retorno local es @retContactInformation. Las
instrucciones del cuerpo de la función insertan filas en esta variable para generar la tabla resultante devuelta por la
función.

SQL
USE AdventureWorks2008R2;
GO

3
IF OBJECT_ID(N'dbo.ufnGetContactInformation', N'TF') IS NOT NULL
DROP FUNCTION dbo.ufnGetContactInformation;
GO
CREATE FUNCTION dbo.ufnGetContactInformation(@ContactID int)
RETURNS @retContactInformation TABLE
(
-- Columns returned by the function
ContactID int PRIMARY KEY NOT NULL,
FirstName nvarchar(50) NULL,
LastName nvarchar(50) NULL,
JobTitle nvarchar(50) NULL,
ContactType nvarchar(50) NULL
)
AS
-- Returns the first name, last name, job title, and contact type for the specified contact.
BEGIN
DECLARE
@FirstName nvarchar(50),
@LastName nvarchar(50),
@JobTitle nvarchar(50),
@ContactType nvarchar(50);
-- Get common contact information
SELECT
@ContactID = BusinessEntityID,
@FirstName = FirstName,
@LastName = LastName
FROM Person.Person
WHERE BusinessEntityID = @ContactID;
-- Get contact job title
SELECT @JobTitle =
CASE
-- Check for employee
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM')
THEN (SELECT JobTitle
FROM HumanResources.Employee AS e
WHERE e.BusinessEntityID = @ContactID)
-- Check for vendor
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC')
THEN (SELECT ct.Name
FROM Person.ContactType AS ct
INNER JOIN Person.BusinessEntityContact AS bec
ON bec.ContactTypeID = ct.ContactTypeID
WHERE bec.PersonID = @ContactID)

-- Check for store


WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC')
THEN (SELECT ct.Name
FROM Person.ContactType AS ct
INNER JOIN Person.BusinessEntityContact AS bec
ON bec.ContactTypeID = ct.ContactTypeID
WHERE bec.PersonID = @ContactID)
ELSE NULL
END;
-- Get contact type
SET @ContactType =
CASE
-- Check for employee
WHEN EXISTS(SELECT * FROM Person.Person AS p

4
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM')
THEN 'Employee'
-- Check for vendor
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC')
THEN 'Vendor Contact'
-- Check for store
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC')
THEN 'Store Contact'
-- Check for individual consumer
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'IN')
THEN 'Consumer'
-- Check for general contact
WHEN EXISTS(SELECT * FROM Person.Person AS p
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'GC')
THEN 'General Contact'
END;
-- Return the information to the caller
IF @ContactID IS NOT NULL
BEGIN
INSERT @retContactInformation
SELECT @ContactID, @FirstName, @LastName, @JobTitle, @ContactType;
END;
RETURN;
END;
GO

En el siguiente ejemplo se utiliza la función con valores de tabla dbo.ufnGetContactInformation en la cláusula FROM de
dos instrucciones SELECT.

SQL
USE AdventureWorks2008R2;
GO
SELECT ContactID, FirstName, LastName, JobTitle, ContactType
FROM dbo.ufnGetContactInformation(1209);
GO
SELECT ContactID, FirstName, LastName, JobTitle, ContactType
FROM dbo.ufnGetContactInformation(5);
GO

Funciones insertadas definidas por el usuario


http://msdn.microsoft.com/es-es/library/ms189294.aspx

Las funciones insertadas definidas por el usuario son un subconjunto de funciones definidas por el usuario que devuelven
un tipo de datos table. Las funciones insertadas pueden utilizarse para obtener la funcionalidad de vistas con parámetros.

En el ejemplo siguiente se devuelven los nombres de almacén y las ciudades de una región especificada.

USE AdventureWorks2008R2;
GO
CREATE VIEW CustomersByRegion
AS

5
SELECT DISTINCT S.Name AS Store, A.City
FROM Sales.Store AS S
JOIN Sales.BusinessEntityAddress AS BEA ON BEA.BusinessEntityID = S.BusinessEntityID
JOIN Person.Address AS A ON A.AddressID = BEA.AddressID
JOIN Person.StateProvince SP ON
SP.StateProvinceID = A.StateProvinceID
WHERE SP.Name = N'Washington';
GO

Esta vista se puede mejorar haciéndola más generalizada y permitiendo a los usuarios especificar la región que desean ver.
No obstante, las vistas no admiten parámetros en las condiciones de búsqueda especificadas en la cláusula WHERE. Las
funciones insertadas definidas por el usuario pueden utilizarse para admitir parámetros en las condiciones de búsqueda
especificadas en la cláusula WHERE. En el ejemplo siguiente se crea una función insertada que permite a los usuarios
especificar la región en la consulta:

SQL
USE AdventureWorks2008R2;
GO

IF OBJECT_ID(N'Sales.ufn_CustomerNamesInRegion', N'IF') IS NOT NULL


DROP FUNCTION Sales.ufn_CustomerNamesInRegion;
GO
CREATE FUNCTION Sales.ufn_CustomerNamesInRegion
( @Region nvarchar(50) )
RETURNS table
AS
RETURN (
SELECT DISTINCT s.Name AS Store, a.City
FROM Sales.Store AS s
INNER JOIN Person.BusinessEntityAddress AS bea
ON bea.BusinessEntityID = s.BusinessEntityID
INNER JOIN Person.Address AS a
ON a.AddressID = bea.AddressID
INNER JOIN Person.StateProvince AS sp
ON sp.StateProvinceID = a.StateProvinceID
WHERE sp.Name = @Region
);
GO
-- Example of calling the function for a specific region
SELECT *
FROM Sales.ufn_CustomerNamesInRegion(N'Washington')
ORDER BY City;
GO

Reglas de las funciones insertadas definidas por el usuario

Las funciones insertadas definidas por el usuario siguen las reglas siguientes:

 La cláusula RETURNS sólo contiene la palabra clave table. No es necesario definir el formato de una variable de
retorno, ya que se define mediante el formato del conjunto de resultados de la instrucción SELECT en la cláusula
RETURN.
 function_body no está delimitada por BEGIN ni END.
 La cláusula RETURN contiene una sola instrucción SELECT entre paréntesis. El conjunto de resultados de la
instrucción SELECT forma la tabla devuelta por la función. La instrucción SELECT utilizada en una función insertada
está sujeta a las mismas restricciones que las instrucciones SELECT utilizadas en las vistas.

6
 La función con valores de tabla sólo acepta constantes o argumentos @local_variable.

Funciones insertadas y vistas indizadas

Las funciones insertadas también pueden utilizarse para aumentar la eficacia de las vistas indizadas. Por sí misma, la vista
indizada no puede utilizar parámetros en las condiciones de búsqueda de su cláusula WHERE para adaptar a usuarios
específicos el conjunto de resultados almacenado. No obstante, se puede definir una vista indizada que almacene un
conjunto completo de datos que coincida con la vista y, a continuación, definir una función insertada para la vista indizada
con condiciones de búsqueda con parámetros que permitan a los usuarios adaptar los resultados. Si la definición de la
vista es compleja, la mayor parte del trabajo realizado para generar un conjunto de resultados incluye operaciones como
la de generar agregados o la de combinar varias tablas al crear el índice clúster en la vista. Si después crea una función
insertada que haga referencia a la vista indizada, la función puede aplicar los filtros con parámetros del usuario para
devolver filas específicas del conjunto de resultados materializado de la vista indizada. Por ejemplo:

1. Se define una vista vw_QuarterlySales que agrega todos los datos de ventas a un conjunto de resultados, y éste
presenta los datos de ventas de todos los almacenes, resumidos y por trimestres.
2. Se crea un índice clúster en vw_QuarterlySales para materializar un conjunto de resultados que contenga los datos
resumidos.
3. Se crea una función insertada para filtrar los datos resumidos:

CREATE FUNCTION dbo.ufn_QuarterlySalesByStore


( @StoreID int )
RETURNS table
AS
RETURN (
SELECT *
FROM SalesDB.dbo.vw_QuarterlySales
WHERE StoreID = @StoreID
)
4. Los usuarios pueden entonces obtener los datos de un almacén específico seleccionándolos a partir de la función
insertada:

SELECT *
FROM fn_QuarterlySalesByStore(14432)

La mayor parte del trabajo necesario para atender las consultas emitidas en el paso 4 es agregar los datos de ventas por
trimestre. Este trabajo se hace una vez en el paso 2. Cada instrucción SELECT individual del paso 4 utiliza la
función fn_QuarterlySalesByStore para filtrar los datos agregados específicos de un almacén.

Funciones deterministas y no deterministas


http://msdn.microsoft.com/es-es/library/ms178091.aspx

Las funciones deterministas devuelven el mismo resultado cada vez que se llaman con un conjunto específico de valores
de entrada y cuando el estado de la base de datos es el mismo. Las funciones no deterministas pueden devolver
resultados diferentes cada vez que se llaman con un conjunto específico de valores de entrada aunque el estado de la
base de datos a la que tienen acceso permanezca sin cambios.

Son varias las propiedades de las funciones definidas por el usuario que determinan la capacidad de SQL Server Database
Engine (Motor de base de datos de SQL Server) para indizar los resultados de la función, ya sea mediante índices en
columnas calculadas que llaman a la función o mediante vistas indizadas que hacen referencia a la función. El
determinismo de una función es una propiedad así. Por ejemplo, no se puede crear un índice clúster en una vista si ésta

7
hace referencia a funciones no deterministas. Para obtener más información acerca de las propiedades de las funciones,
incluido el determinismo, vea Directrices para el diseño de funciones definidas por el usuario.

En este tema se identifica el determinismo de las funciones integradas del sistema y el efecto de las funciones definidas
por el usuario en la propiedad determinista cuando ésta contiene una llamada a los procedimientos almacenados
extendidos.

Determinismo de las funciones integradas

El determinismo de las funciones integradas no se ve afectado por el usuario. Las funciones integradas son deterministas
o no deterministas según el modo en que SQL Server implementa cada función.

Todas las funciones integradas de cadena y de agregados son deterministas. Para obtener una lista de estas funciones,
vea Funciones de agregado (Transact-SQL) y Funciones de cadena (Transact-SQL).

Las siguientes funciones integradas procedentes de categorías que no son de agregados ni de cadena siempre
son deterministas.

ABS DATEDIFF POWER

ACOS DAY RADIANS

ASIN DEGREES ROUND

ATAN EXP SIGN

ATN2 FLOOR SIN

CEILING ISNULL SQUARE

COALESCE ISNUMERIC SQRT

COS LOG TAN

COT LOG10 YEAR

DATALENGTH MONTH

DATEADD NULLIF

Las siguientes funciones no siempre son deterministas, pero pueden utilizarse en vistas indizadas o en índices
de columnas calculadas si se especifican de una manera determinista.

Función Comentarios (sintaxis de MDX)


CAST Determinista, a menos que se utilice con datetime, smalldatetime o sql_variant.

8
CONVERT Determinista, a menos que se cumpla una de estas condiciones:
 El tipo de origen es sql_variant.
 El tipo de destino es sql_variant y el tipo de origen no es determinista.
 El tipo de origen o destino es datetime o smalldatetime, el otro tipo de origen o destino es
una cadena de caracteres, y se especifica un tipo de estilo no determinista. Para que sea
determinista, el parámetro de estilo debe ser una constante. Además, los estilos menores o
iguales que 100 son no deterministas, salvo los estilos 20 y 21. Los estilos mayores que
100 son deterministas, salvo los estilos 106, 107, 109 y 113.

CHECKSUM Determinista, excepto CHECKSUM(*).

ISDATE Determinista solo si se utiliza con la función CONVERT, se especifica el parámetro de estilo
CONVERT y el estilo no es igual a 0, 100, 9 ni 109.

RAND RAND es determinista solo cuando se especifica un parámetro seed.

Todas las funciones de configuración, cursores, metadatos, seguridad y estadísticas del sistema no son deterministas. Para
obtener una lista de estas funciones, vea Funciones de configuración (Transact-SQL), Funciones del cursor (Transact-
SQL), Funciones de metadatos (Transact-SQL), Funciones de seguridad (Transact-SQL) y Funciones estadísticas del sistema
(Transact-SQL).

Las siguientes funciones integradas, procedentes de otras categorías, no son deterministas nunca.

@@CONNECTIONS @@TOTAL_WRITE

@@CPU_BUSY CURRENT_TIMESTAMP

@@DBTS GETDATE

@@IDLE GETUTCDATE

@@IO_BUSY GET_TRANSMISSION_STATUS

@@MAX_CONNECTIONS MIN_ACTIVE_ROWVERSION

@@PACK_RECEIVED NEWID

@@PACK_SENT NEWSEQUENTIALID

@@PACKET_ERRORS PARSENAME

@@TIMETICKS RAND

@@TOTAL_ERRORS TEXTPTR

@@TOTAL_READ

Llamar a procedimientos almacenados extendidos desde funciones

9
Las funciones que llaman a procedimientos almacenados extendidos no son deterministas porque estos pueden producir
efectos secundarios en la base de datos. Los efectos secundarios son cambios de un estado global de la base de datos,
como una actualización de una tabla, o de un recurso externo, como un archivo o la red (por ejemplo, la modificación de
un archivo o el envío de un mensaje de correo electrónico). No debe confiar en la devolución de un conjunto de
resultados coherente al ejecutar un procedimiento almacenado extendido desde una función definida por el usuario. No
se recomienda el uso de funciones definidas por el usuario que producen efectos secundarios en la base de datos.

Cuando se llama desde una función, el procedimiento almacenado extendido no puede devolver conjuntos de resultados
al cliente. Las API de Servicios abiertos de datos que devuelven conjuntos de resultados al cliente tienen un código de
retorno FAIL.

El procedimiento almacenado extendido puede volver a conectarse a SQL Server. Sin embargo, no puede combinar la
misma transacción como la función original que invocó el procedimiento almacenado extendido.

De forma similar a las invocaciones desde un lote o un procedimiento almacenado, el procedimiento almacenado
extendido se ejecuta en el contexto de la cuenta de seguridad de Microsoft Windows con la que se ejecuta SQL Server. El
propietario del procedimiento almacenado extendido debe tener esto en cuenta al conceder permisos a otros usuarios
para ejecutar el procedimiento.

Volver a escribir procedimientos almacenados como


funciones
http://msdn.microsoft.com/es-es/library/ms187650.aspx

En este tema se describe la manera de determinar si se vuelve a escribir la lógica de un procedimiento


almacenado como una función definida por el usuario. Por ejemplo, si desea invocar un procedimiento
almacenado directamente desde una consulta, reorganice el código como si fuera una función definida por el
usuario.

En general, si el procedimiento almacenado devuelve un solo conjunto de resultados, defina una función con
valores de tabla. Si el procedimiento almacenado calcula un valor escalar, defina una función escalar.

Criterios para las funciones con valores de tabla

Si un procedimiento almacenado cumple los siguientes criterios, se puede volver a escribir como una función
con valores de tabla:

 La lógica se puede expresar en una sola instrucción SELECT, pero es un procedimiento almacenado en
lugar de una vista por el mero hecho de que requiere parámetros. Este escenario puede controlarse con
una función con valores de tabla insertada.
 Este procedimiento almacenado no realiza operaciones de actualización, excepto en variables de tabla.

 No son necesarias las instrucciones EXECUTE dinámicas.

 El procedimiento almacenado devuelve un conjunto de resultados.

 El objetivo principal de un procedimiento almacenado es generar resultados intermedios que se cargan


en una tabla temporal, que luego se consulta en una instrucción SELECT. Las instrucciones

10
INSERT...EXEC pueden escribirse utilizando funciones con valores de tabla. Considere, por ejemplo, la
secuencia siguiente:

INSERT #temp EXEC sp_getresults


SELECT ...
FROM #temp, t1
WHERE ...

El procedimiento almacenado sp_getresults se puede volver a escribir como una función con valores de
tabla, por ejemplo fn_results(), que significa que la instrucción anterior puede volver a escribirse como:

INSERT #temp
SELECT ...
FROM fn_results(), t1
WHERE ...

Volver a escribir procedimientos almacenados extendidos


mediante CLR

Las funciones CLR suponen una alternativa más confiable y escalable frente a los procedimientos almacenados
extendidos. Muchos procedimientos almacenados extendidos realizan tareas de cálculo que son difíciles de
expresar en Transact-SQL. Tales procedimientos almacenados se pueden volver a escribir mediante CLR para
disfrutar de las ventajas descritas anteriormente. Además, los procedimientos almacenados extendidos que
devuelven conjuntos de resultados mediante el acceso a un recurso externo, como un archivo o un servicio Web,
se pueden volver a escribir mediante una función con valores de tabla CLR. Para obtener más información,
vea Crear funciones CLR.

11

Potrebbero piacerti anche