Trans SQL
Trans SQL
9.1. Introducción
Hasta ahora hemos estudiado sentencias SQL orientadas a realizar una determinada tarea sobre la
base de datos como definir tablas, obtener información de las tablas, actualizarlas; estas sentencias las
hemos ejecutado desde el editor de consultas del MSSMS de una en una o a lo sumo una a
continuación de la otra dentro de la misma consulta formando un lote de instrucciones.
Las sentencias que ya conocemos son las que en principio forman parte de cualquier lenguaje SQL.
Ahora veremos que TRANSACT-SQL va más allá de un lenguaje SQL cualquiera ya que aunque no
permita:
Crear aplicaciones ejecutables, sino elementos que en algún momento llegarán al servidor de datos y
serán ejecutados.
Tipos de datos.
Definición de variables.
Gestión de excepciones.
Funciones predefinidas.
Elementos para la visualización, que permiten mostrar mensajes definidos por el usuario gracias
a la cláusula PRINT.
Estas características nos van a permitir crear bloques de código orientados a realizar operaciones más
complejas. Estos bloques no son programas sino procedimientos o funciones que podrán ser llamados
en cualquier momento.
En SQL Server 2005 podemos definir tres tipos de bloques de código, los procedimientos almacenados,
los desencadenadores (o triggers) y funciones definidas por el usuario.
Empezaremos por los procedimientos almacenados, veremos primero las sentencias para crear y
eliminar procedimientos almacenados, luego estudiaremos las instrucciones Transact-SQL más propias
de un lenguaje de programación nombradas en el tema de Introducción al Transact-SQL como son por
ejemplo los bucles y estructuras condicionales. Estas instrucciones las utilizaremos dentro de
procedimientos almacenados pero veremos que también nos servirán para definir otros bloques de
código.
Terminaremos esta unidad de programación estudiando los disparadores o Triggers muy similares a
los procedimientos almacenados que difieren básicamente en la forma en que entran en
funcionamiento.
9.2. Procedimientos almacenados STORE PROCEDURE
Un procedimiento almacenado (STORE PROCEDURE) está formado por un conjunto de instrucciones
Transact-SQL que definen un determinado proceso, puede aceptar parámetros de entrada y devolver
un valor o conjunto de resultados. Este procedimiento se guarda en el servidor y puede ser ejecutado
en cualquier momento.
Los procedimientos almacenados se diferencian de las instrucciones SQL ordinarias y de los lotes de
instrucciones SQL en que están precompilados. La primera vez que se ejecuta un procedimiento, el
procesador de consultas de SQL Server lo analiza y prepara un plan de ejecución que se almacena en
una tabla del sistema. Posteriormente, el procedimiento se ejecuta según el plan almacenado. Puesto
que ya se ha realizado la mayor parte del trabajo de procesamiento de consultas, los procedimientos
almacenados se ejecutan casi de forma instantánea por lo que el uso de procedimientos almacenados
mejora notablemente la potencia y eficacia del SQL.
SQL Server incorpora procedimientos almacenados del sistema, se encuentran en la base de datos
master y se reconocen por su nombre, todos tienen un nombre que empieza por sp_. Permiten
recuperar información de las tablas del sistema y pueden ejecutarse en cualquier base de datos del
servidor.
También están los procedimientos de usuario, los crea cualquier usuario que tenga los permisos
oportunos.
Tanto los procedimientos temporales como los no temporales se crean y ejecutan de la misma forma,
el nombre que le pongamos indicará de qué tipo es el procedimiento.
Transact-SQL permite abreviar la palabra reservada PROCEDURE por PROC sin que ello afecte a la
funcionalidad de la instrucción.
Ejemplos:
DROP PROCEDURE Dice_Hola;
Para eliminar varios procedimientos de golpe, indicamos sus nombres separados por comas:
Para crear un procedimiento almacenado como hemos dicho se emplea la instrucción CREATE
PROCEDURE:
Las instrucciones CREATE PROCEDURE no se pueden combinar con otras instrucciones SQL en el mismo
lote.
Después del verbo CREATE PROCEDURE indicamos el nombre del procedimiento, opcionalmente
podemos incluir el nombre del esquema donde queremos que se cree el procedimiento, por defecto se
creará en dbo. Ya que Sqlserver utiliza el prefijo sp_ para nombrar los procedimientos del sistema se
recomienda no utilizar nombres que empiecen por sp_.
Como se puede deducir de la sintaxis (no podemos indicar un nombre de base de datos asociado al
nombre del procedimiento) sólo se puede crear el procedimiento almacenado en la base de datos
actual, no se puede crear en otra base de datos.
Si queremos definir un procedimiento temporal local el nombre deberá empezar por una almohadilla
(#) y si el procedimiento es temporal global el nombre debe de empezar por ##.
Es equivalente a
Los parámetros son locales para el procedimiento; los mismos nombres de parámetro se pueden
utilizar en otros procedimientos. De manera predeterminada, los parámetros sólo pueden ocupar el
lugar de expresiones constantes; no se pueden utilizar en lugar de nombres de tabla, nombres de
columna o nombres de otros objetos de base de datos.
VARYING Sólo se aplica a los parámetros de tipo cursor por lo que se explicará cuando se expliquen los
cursores.
Indica que se trata de un parámetro de salida. El valor de esta opción puede devolverse a la instrucción
EXECUTE que realiza la llamada.
Procedimiento básico
En este caso, como la llamada es la primera del lote (va detrás del GO) podíamos haber obviado la
palabra EXEC y haber escrito directamente:
Dice_Hola
Con un parámetro de entrada (la palabra que queremos que escriba)
Aquí hemos hecho dos llamadas, una con el valor ‘Lo que quiera’ y otra con el valor ‘Otra cosa’.
USE Biblio;
--DROP PROC VerUsuariosPoblacion; --La comentamos la primera vez
GO
CREATE PROCEDURE VerUsuariosPoblacion @pob CHAR(30),@pro CHAR(30)
AS
SELECT * FROM usuarios WHERE poblacion=@pob AND provincia = @pro;
GO
EXEC VerUsuariosPoblacion Madrid, Valencia
indicando sólo el valor de los parámetros (en este caso los tenemos que indicar en el mismo orden en
que están definidos) como en el ejemplo anterior, o bien indicando el nombre del parámetro:
Indicar el nombre del parámetro en la llamada también nos permite indicar los valores en cualquier
orden, la siguiente llamada es equivalente a la anterior, hemos invertido el orden y se ejecuta igual:
En este procedimiento todos los parámetros son obligatorios, no deja llamar con un solo parámetro.
Para definir un parámetro opcional tenemos que asignarle un valor por defecto en la definición del
procedimiento.
En este caso, en la llamada sólo hemos indicado un valor, para el primer parámetro, el paramétro
opcional no lo hemos indicado y se rellenará con el valor por defecto que indicamos en la definición.
Lo podemos hacer así porque el parámetro opcional es el último de la lista de parámetros. Cuando el
parámetro opcional no es el último la llamada tiene que ser diferente, tenemos que nombrar los
parámetros en la llamada, al menos a partir del parámetro opcional.
Da error.
Esta forma da error, debemos utilizar la palabra DEFAULT o indicar el nombre de todos los parámetros
que van detrás del opcional.
EXEC VerUsuariosPoblacion3 a,DEFAULT,'Madrid'
Para poder recoger el valor devuelto por el procedimiento, en la llamada se tiene que indicar una
variable donde guardar ese valor.
Ejemplo:
Definimos el procedimiento ultimo_contrato que nos devuelte la fecha en que se firmó el último
contrato en una determinada oficina. El procedimiento tendrá pues dos parámetros, uno de entrada
para indicar el número de la oficina a considerar y uno de salida que devolverá la fecha del contrato
más reciente de entre los empleados de esa oficina.
USE Gestion
GO
CREATE PROC ultimo_contrato @ofi INT, @fecha DATETIME OUTPUT
AS
SELECT @fecha=(SELECT MAX(contrato) FROM empleados WHERE oficina=@ofi)
GO
Con @fecha DATETIME OUTPUT indicamos que el parámetro @fecha es de salida, el proceso que
realice la llamada podrá recoger su valor después de ejecutar el procedimiento.
En la llamada, para los parámetros de salida, en vez de indicar un valor de entrada se indica un nombre
de variable, variable que recogerá el valor devuelto por el procedimiento sin olvidar la palabra
OUTPUT:
RETURN
RETURN [expresion_entera]
Expresion_entera es el valor entero que se devuelve.
A menos que se especifique lo contrario, todos los procedimientos almacenados del sistema devuelven
el valor 0. Esto indica que son correctos y un valor distinto de cero indica que se ha producido un error.
Cuando se utiliza con un procedimiento almacenado, RETURN no puede devolver un valor NULL. Si un
procedimiento intenta devolver un valor NULL (por ejemplo, al utilizar RETURN @var si @var es NULL),
se genera un mensaje de advertencia y se devuelve el valor 0.
Si queremos recoger el valor de estado devuelto por el procedimiento la llamada debe ser distinta, y
seguir el siguiente modelo:
Con el procedimiento del punto anterior no se puede utilizar esta forma de devolver un resultado
porque lo que se devuelve es una fecha, no es un valor entero, pero si quisiéramos definir un
procedimiento que nos devuelva el número de empleados de una oficina podríamos hacerlo de dos
formas:
USE Gestion
GO
CREATE PROC trabajadores @ofi INT, @num INT OUTPUT
AS
SELECT @num=(SELECT COUNT(*) FROM empleados WHERE oficina=@ofi)
GO
Para obtener en la variable @var el resultado devuelto por el procedimiento la llamada sería:
Para obtener en la variable @var el resultado devuelto por el procedimiento la llamada sería:
DECLARE @var INT;
EXEC @var= trabajadores2 12
PRINT @var