Introducción
Por lo general, los administradores de bases de datos prefieren los procedimientos almacenados en SQL en vez de funciones en SQL Server. ¿Es esta una buena práctica?
En este artículo, le vamos a enseñar cómo poder crear procedimientos y funciones almacenados en SQL Server y vamos a mostrar las ventajas y desventajas de cada uno de ellos. En los ejemplos que vamos a usar en este artículo, utilizaremos funciones escalares definidas por el usuario, también conocidas como UDF. Mostraremos algunas funciones con valores de tabla en el futuro. Las funciones CLR no se cubrirán aquí.
Incluiremos los siguientes temas:
- Crear un “Hello World” en un procedimiento almacenado frente a una función
- Invocar un procedimiento almacenado versus invocar una función
- Usar variables en un procedimiento almacenado frente a una función
- Reusabilidad
- Invocar funciones/procedimientos dentro de funciones/ procedimientos
Empecemos
1. Crear un “Hello world” en un procedimiento almacenado en SQL versus una función
Vamos a crear un simple “Hello world” en un procedimiento almacenado y una función para verificar cuál es más fácil de poder crear.
Primero empecemos creando un procedimiento de almacenado simple usando la declaración en SSMS:
1 2 3 4 5 |
CREATE PROCEDURE HelloWorldprocedure AS PRINT 'Hello World' |
Ejecute el código y después llame al procedimiento almacenado en SQL:
1 2 3 |
exec HelloWorldprocedure |
Si ejecuta el código, podrá ver el mensaje “Hello World”:
Ahora intentemos hacer lo mismo con una función:
1 2 3 4 5 6 7 8 |
CREATE FUNCTION dbo.helloworldfunction() RETURNS varchar(20) AS BEGIN RETURN 'Hello world' END |
Podemos llamar a la función utilizando un select:
La función devolverá el siguiente mensaje:
Si se compara el código, la función requiere más código para hacer lo mismo. Los bloques BEGIN y END son obligatorios en una función, mientras que el procedimiento almacenado no los requiere si es solo una línea. En una función, es obligatorio utilizar los argumentos RETURNS y RETURN, mientras que en un procedimiento almacenado no es necesario.
En pocas palabras, un procedimiento almacenado es mucho más flexible para escribir cualquier código que uno desee, mientras que las funciones tienen una estructura y funcionalidad rígidas.
2. Invocar un procedimiento almacenado en SQL frente a Invocar una función
Usted puede invocar un procedimiento almacenado de diferentes maneras:
1 2 3 4 5 6 |
exec HelloWorldprocedure execute HelloWorldprocedure execute dbo.HelloWorldprocedure HelloWorldprocedure |
Puede invocar utilizando exec o execute e incluso puede invocar el procedimiento almacenado sin la instrucción execute. No es necesario que se tenga que especificar el nombre del esquema.
The functions are less flexible. You need to specify the schema to invoke it (which is a good practice to avoid conflicts with other object with the same name and different schema).
Llamemos a una función sin el esquema:
1 2 3 |
select helloworldfunction() as regards |
El mensaje que se muestra es el siguiente:
El mensaje 195, Nivel 15, Estado 10, Línea 20 ‘helloworldfunction’ no es un nombre de función incorporado reconocido
Como puede ver, el nombre del esquema es obligatorio para poder invocar una función:
1 2 3 |
select dbo.helloworldfunction() as regards |
3. Usar variables en un procedimiento almacenado en SQL vs a una función
Ahora vamos a convertir grados Celsius a Fahrenheit utilizando procedimientos y funciones almacenados para ver las diferencias. Empecemos con un procedimiento almacenado:
1 2 3 4 5 6 |
CREATE PROCEDURE CONVERTCELSIUSTOFAHRENHEIT @celsius real as select @celsius*1.8+32 as Fahrenheit |
Celsius es el parámetro de entrada y estamos haciendo los cálculos en la instrucción select para convertir a grados Fahrenheit.
Si invocamos el procedimiento almacenado, vamos a verificar el resultado convirtiendo 0 °C:
1 2 3 |
exec CONVERTCELSIUSTOFAHRENHEIT 0 |
El resultado será 32 °F:
Tratemos de hacer lo mismo con una función:
1 2 3 4 5 6 7 8 9 |
CREATE FUNCTION dbo.f_celsiustofahrenheit(@celcius real) RETURNS real AS BEGIN RETURN @celcius*1.8+32 END |
Puede llamar a la función creada de la siguiente manera:
1 2 3 |
select dbo.f_celsiustofahrenheit(0) as fahrenheit |
Estamos convirtiendo 0° C a °F. Como se puede ver, el código es muy simple en ambos casos.
4. Reusabilidad
La principal ventaja de una función es que esta puede reutilizarse en código. Como por ejemplo, puede hacer lo siguiente:
1 2 3 |
select CONCAT(dbo.helloworldfunction(),', welcome to sqlshack') Regards |
En este ejemplo, estamos concatenando la función del ejemplo 1 con una cadena. El resultado va a ser el siguiente:
Como usted puede ver, se puede concatenar fácilmente una función con una cadena. Para realizar algo similar con un procedimiento almacenado en SQL, vamos a necesitar una variable de salida en un procedimiento almacenado para poder concatenar la variable de salida con una cadena. Vamos a echar un vistazo al procedimiento almacenado:
1 2 3 4 5 6 |
create procedure outputparam @paramout varchar(20) out as select @paramout='Hello world' |
El procedimiento consta en asignar la cadena “Hello World” a un parámetro de salida. Puede utilizar la palabra de salida o salir para especificar que el parámetro es un parámetro de salida.
El código puede ser simple, pero tiene que llamar al procedimiento para usar el parámetro de salida que se concatena, es un poco más complejo que una función:
1 2 3 4 5 6 |
declare @message varchar(20) exec outputparam @paramout=@message out select @message as regards select CONCAT(@message,', welcome to sqlshack') |
Como puede apreciar, se debe declarar una nueva variable llamada @message o cualquier otro nombre de su preferencia. Cuando llama al procedimiento almacenado, se debe especificar que es un parámetro externo. Una ventaja de los procedimientos almacenados es que puede obtener varios parámetros mientras que, en las funciones, solo se puede devolver una variable (función escalar) o una tabla (funciones con valores de tabla).
5. Invocar funciones/Procedimientos dentro de funciones/Procedimientos almacenados en SQL
¿Podemos invocar procedimientos almacenados dentro de una función?
Vamos a echar un vistazo:
1 2 3 4 5 6 7 8 9 10 |
CREATE FUNCTION dbo.procedureinsidefunction() RETURNS varchar(22) AS BEGIN execute HelloWorldprocedure Declare @hellovar varchar(22)=', welcome to sqlshack' RETURN @hellovar END |
La función va a invocar el procedimiento “Hello World” creado en la sección 1.
Si invocamos la función, tendremos el siguiente mensaje:
Msg 557, Nivel 16, Estado 2, Línea 65 Solo se pueden ejecutar funciones y algunos procedimientos almacenados extendidos desde una función.
Como se puede apreciar, no es posible llamar a un procedimiento almacenado desde una función. ¿Se puede llamar a una función desde un procedimiento almacenado?
Aquí está el procedimiento:
1 2 3 |
create procedure functioninsideprocedure as select dbo.helloworldfunction() |
Si invocamos el procedimiento almacenado en SQL, podremos verificar si este funciona o no:
1 2 3 |
exec functioninsideprocedure |
El resultado que se muestra es el siguiente:
Como se puede apreciar, es posible invocar funciones dentro de un procedimiento almacenado y no se puede invocar un procedimiento almacenado dentro de una función.
Puede invocar una función dentro de una función. El siguiente código muestra un ejemplo simple:
1 2 3 4 5 6 7 8 9 |
CREATE FUNCTION dbo.functioninsidefunction() RETURNS varchar(50) AS BEGIN RETURN dbo.helloworldfunction() END |
Podemos llamar a la función como de costumbre:
1 2 3 |
select dbo.functioninsidefunction() as regards |
¿Es posible que podamos llamar a procedimientos dentro de otros procedimientos?
Sí se puede. Aquí tienes un ejemplo al respecto:
1 2 3 4 5 |
create procedure procedureinsideprocedure as execute dbo.HelloWorldprocedure |
Puede ejecutar el procedimiento como de costumbre:
1 2 3 |
exec dbo.procedureinsideprocedure |
Conclusiones
Los procedimientos almacenados en SQL son mucho más fáciles de crear y las funciones tienen una estructura más rígida y admiten menos cláusulas y funcionalidades. Pero, por otro lado, usted puede usar fácilmente los resultados de la función en T-SQL. Le mostramos cómo concatenar una función con una cadena. La manipulación de resultados de un procedimiento almacenado es más compleja.
En una función escalar, puede devolver solo una variable y en un procedimiento almacenado múltiples variables. Sin embargo, para llamar a las variables de salida en un procedimiento almacenado, es necesario el declarar variables fuera del procedimiento para poder invocarlo.
Asimismo, no puede invocar procedimientos dentro de una función. Pero, por otro lado, en un procedimiento se puede invocar funciones y procedimientos almacenados.
Finalmente, es muy importante mencionar algunos problemas de rendimiento cuando utilizamos funciones. Sin embargo, esta desventaja se explicará en un próximo artículo, Funciones y comparaciones de procedimientos almacenados en SQL Server.
Referencias
Para obtener más información, consulte estos enlaces:
- Cómo construir un cubo desde cero usando SQL Server Analysis Services (SSAS) - December 16, 2019
- Fecha de conversión de SQL - December 11, 2019
- Funciones frente a los procedimientos almacenados en SQL Server - October 14, 2019