Programación Con Transact SQL
Programación Con Transact SQL
Programación Con Transact SQL
Introducción
Sin embargo, SQL es la herramienta ideal para trabajar con bases de datos. Cuando
se desea realizar una aplicación completa para el manejo de una base de datos
relacional, resulta necesario utilizar alguna herramienta que soporte la capacidad de
consulta del SQL y la versatilidad de los lenguajes de programación tradicionales.
Transact SQL es el lenguaje de programación que proporciona Microsoft SQL Server
para extender el SQL estándar con otro tipo de instrucciones y elementos propios de
los lenguajes de programación .
Con Transact SQL vamos a poder programar las unidades de programa de la base
de datos SQL Server, están son:
• Procedimientos almacenados
• Funciones
• Triggers
• Scripts
/*
Este es un comentario con varias líneas.
Conjunto de Lineas.
*/
declare @nombre varchar(50)-- declare declara una variable
-- @nombre es el identificador de la
-- variable de tipo varchar
set @nombre = 'www.devjoker.com' -- El signo = es un operador
-- www.devjoker.com es un literal
print @Nombre -- Imprime por pantalla el valor de @nombre.
-- No diferencia mayúsculas ni minúsculas
Scripts y lotes.
Un script está compuesto por uno o varios lotes. Un lote delimita el alcance de las
variables y sentencias del script. Dentro de un mismo script se diferencian los
diferentes lotes a través de las instrucción GO.
Transact SQL proporciona una variedad predefinida de tipos de datos . Casi todos
los tipos de datos manejados por Transact SQL son similares a los soportados
por SQL.
SQL Server dispone de varios tipos de datos númericos. Cuanto mayor sea el
número que puedan almacenar mayor será en consecuencia el espacio utilizado para
almacenarlo. Como regla general se recomienda usar el tipo de dato mínimo posible.
Todos los dato numéricos admiten el valor NULL.
Bit. Una columna o variable de tipo bit puede almacenar el rango de valores de 1
a 0.
Int. Una columna o variable de tipo int puede almacenar el rango de valores -231 a
231-1 .
BigInt. Una columna o variable de tipo bigint puede almacenar el rango de valores
-263 a 263-1 .
Float. Una columna de datos float puede almacenar el rango de valores -1,79x-
10308 a 1,79x-10308, , si la definimos con el valor máxmo de precisión. La precisión
puede variar entre 1 y 53.
Money. Almacena valores númericos monetarios de -263 a 263-1, con una precisión
de hasta diexz milesimas de la unidad monetaria.
Todos los tipos de datos enteros pueden marcarse con la propiedad identity para
hacerlos autonuméricos.
Char(n). Almacena n caracteres en formato ASCII, un byte por cada letra. Cuando
almacenamos datos en el tipo char, siempre se utilizan los n caracteres indicados,
incluso si la entrada de datos es inferior. Por ejemplo, si en un char(5), guardamos el
valor 'A', se almacena 'A ', ocupando los cinco bytes.
Datetime. Almacena fechas con una precision de milisegundo. Debe usarse para
fechas muy especificas.
SmallDatetime. Almacena fechas con una precision de minuto, por lo que ocupa la
mitad de espacio de que el tipo datetime, para tablas que puedan llegar a tener
muchos datos es un factor a tener muy en cuenta.
Binary. Se utiliza para almacenar datos binarios de longitud fija, con una longitud
máxima de 8000 bytes.
Varbinary. Se utiliza para almacenar datos binarios de longitud variable, con una
longitud máxima de 8000 bytes..Es muy similar a binary, salvo que varbinary utiliza
menos espacio en disco.
XML.Una de las grandes mejoras que incorpora SQL Server 2005 es el soporte
nativo para XML. Como podemos deducir, este tipo de datos se utiliza para
almacenar XML.
/*
Este es un comentario con varias líneas.
Conjunto de Lineas.
*/
declare @nombre varchar(50)-- declare declara una variable
-- @nombre es el identificador de la
-- variable de tipo varchar
set @nombre = 'www.devjoker.com' -- El signo = es un operador
-- www.devjoker.com es un literal
print @Nombre -- Imprime por pantalla el valor de @nombre.
-- No diferencia mayúsculas ni minúsculas
FROM CLIENTES
WHERE ID = 1)
PRINT @nombre
@apellido1 VARCHAR(100),
@apellido2 VARCHAR(100)
SELECT @nombre=nombre ,
@apellido1=Apellido1,
@apellido2=Apellido2
FROM CLIENTES
WHERE ID = 1
PRINT @nombre
PRINT @apellido1
PRINT @apellido2
Un punto a tener en cuenta cuando asignamos variables de este modo, es que si la
consulta SELECT devuelve más de un registro, las variables quedarán asignadas con
los valores de la última fila devuelta.
@apellido1 VARCHAR(100),
@apellido2 VARCHAR(100)
FOR
FROM CLIENTES
OPEN CDATOS
WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT @nombre
PRINT @apellido1
PRINT @apellido2
END
CLOSE CDATOS
DEALLOCATE CDATOS
Veremos los cursores con más detalle más adelante en este tutorial.
Operador de
=
asignación
Operadores + (suma)
aritméticos - (resta)
* (multiplicación)
/ (división)
** (exponente)
% (modulo)
Operadores = (igual a)
relacionales o de <> (distinto de)
comparación != (distinto de)
< (menor que)
> (mayor que)
>= (mayor o igual a)
<= (menor o igual a)
!> (no mayor a)
!< (no menor a)
Operadores lógicos AND (y lógico)
NOT (negacion)
OR (o lógico)
& (AND a nivel de bit)
| (OR a nivel de bit)
^ (OR exclusivo a nivel de bit)
Operador de
+
concatenación
ALL (Devuelve TRUE si el conjunto completo de
comparaciones es TRUE)
ANY(Devuelve TRUE si cualquier elemento del conjunto de
comparaciones es TRUE)
BETWEEN (Devuelve TRUE si el operando está dentro del
intervalo)
Otros
EXISTS (TRUE si una subconsulta contiene filas)
IN (TRUE si el operando está en la lista)
LIKE (TRUE si el operando coincide con un patron)
NOT (Invierte el valor de cualquier operador booleano)
SOME(Devuelve TRUE si alguna de las comparaciones de
un conjunto es TRUE)
Estructuras de control en Transact SQL
Estructura condicional IF
IF (<expresion>)
BEGIN
...
END
ELSE IF (<expresion>)
BEGIN
...
END
ELSE
BEGIN
...
END
IF @diminutivo = 'DJK'
BEGIN
PRINT 'www.devjoker.com'
END
ELSE
BEGIN
PRINT 'Otra Web (peor!)'
END
CASE <expresion>
WHEN <valor_expresion> THEN <valor_devuelto>
WHEN <valor_expresion> THEN <valor_devuelto>
ELSE <valor_devuelto> -- Valor por defecto
END
Ejemplo de CASE.
CASE
WHEN <expresion> = <valor_expresion> THEN <valor_devuelto>
WHEN <expresion> = <valor_expresion> THEN <valor_devuelto>
ELSE <valor_devuelto> -- Valor por defecto
END
Bucle WHILE
WHILE <expresion>
BEGIN
...
END
Estructura GOTO
La sentencia goto nos permite desviar el flujo de ejecución hacia una etiqueta. Fué
muy utilizada en versiones anteriores de SQL Server conjuntamente con la variable
de sistema @@ERROR para el control de errores.
IF @@ERROR > 0
GOTO error
BEGIN TRY
...
END TRY
BEGIN CATCH
...
END CATCH
BEGIN TRY
@dividendo int,
@resultado int
Son:
BEGIN TRY
@dividendo int,
@resultado int
SET @divisor = 0
IF @@ERROR = 0
BEGIN
PRINT 'No hay error'
END
ELSE
BEGIN
PRINT 'Hay error'
END
SET @tipo = 1
SET @clasificacion = 3
IF (@tipo = 1 AND @clasificacion = 3)
BEGIN
RAISERROR ('El tipo no puede valer uno y la clasificacion 3',
16, -- Severidad
1 -- Estado
)
END
La severidad indica el grado de criticidad del error. Admite valores de 0 al 25, pero
solo podemos asignar valores del 0 al 18. Los errores el 20 al 25 son considerados
fatales por el sistema, y cerraran la conexion que ejecuta el comando RAISERROR.
Para asignar valores del 19 al 25 necesitares ser miembros de la función de SQL
Server sysadmin.
La sentencia SELECT nos permite consultar los datos almacenados en una tabla
de la base de datos.
El formato de la sentencia select es:
FROM FAMILIAS
SELECT *
FROM FAMILIAS
Ahora vamos a realizar una consulta obteniendo además de los datos de familias,
los datos de las categorias y los productos.
SELECT *
FROM FAMILIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA
La combinación se realiza a través de la clausula INNER JOIN, que es una clasula
exclusiva, es decir las familias que no tengan categorias y productos asociados no se
devolveran.
SELECT *
FROM FAMILIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA
La cláusula WHERE
FROM FAMILIAS
WHERE CO_FAMILIA = 1
FROM FAMILIAS
WHERE CO_FAMILIA = 1
OR CO_FAMILIA = 2
Podemos agrupar varias valores para una condicion en la clausula IN:
SELECT *
FROM FAMILIAS
WHERE CO_FAMILIA IN ( 1 , 2)
SELECT FAMILIAS.CO_FAMILIA,
FAMILIAS.FAMILIA
FROM FAMILIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
SELECT *
FROM FAMILIAS
FROM FAMILIAS
FROM FAMILIAS
FROM FAMILIAS
FROM FAMILIAS
La cláusula ORDER BY
FROM FAMILIAS
Consultas agregadas
La cláusula GROUP BY
Para cada registro se puede crear un valor agregado si se incluye una función SQL
agregada, como por ejemplo Sum o Count, en la instrucción SELECT. Su sintaxis es:
SELECT COUNT(*)
FROM PRODUCTOS
Este otro ejemplo, muestra la suma del PRECIO de cada uno de los productos que
componen un pedido, para calcular el total del pedido agrupados por los datos del
cliente.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Siempre que incluyamos una clausula WHERE en una consulta agregada esta se
aplica antes de calcular el valor agregado. Es decir, si sumamos el valor de las ventas
por producto, la suma se calcula despues de haber aplicado el filtro impuesto por la
clausula WHERE.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
SUM(PRECIO) -- Total del pedido
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
La cláusula HAVING
Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier
registro agrupado por la cláusula GROUP BY que satisfaga las condiciones de la
cláusula HAVING. Se utiliza la cláusula WHERE para excluir aquellas filas que no
desea agrupar, y la cláusula HAVING para filtrar los registros una vez agrupados.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
SUM(PRECIO) -- Total del pedido
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Funciones agregadas.
Transact SQL pone a nuestra disposición multiples funciones agregadas, las más
comunes son:
• MAX
• MIN
• COUNT
• SUM
• AVG
AVG
AVG(<expr>)
En donde expr representa el campo que contiene los datos numéricos para los que
se desea calcular la media o una expresión que realiza un cálculo utilizando los datos
de dicho campo. La media calculada por Avg es la media aritmética (la suma de los
valores dividido por el número de valores). La función Avg no incluye ningún campo
Null en el cálculo.
SELECT CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Count
COUNT(<expr>)
En donde expr contiene el nombre del campo que desea contar. Los operandos de
expr pueden incluir el nombre de un campo de una tabla, una constante o una
función (la cual puede ser intrínseca o definida por el usuario pero no otras de las
funciones agregadas de SQL). Puede contar cualquier tipo de datos incluso texto.
FROM PEDIDOS
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Max, Min
MIN(<expr>)
MAX(<expr>)
En donde expr es el campo sobre el que se desea realizar el cálculo. Expr pueden
incluir el nombre de un campo de una tabla, una constante o una función (la cual
puede ser intrínseca o definida por el usuario pero no otras de las funciones
agregadas de SQL).
SELECT CLIENTES.NOMBRE,
MIN(PEDIDOS.FX_ALTA),
MAX(PEDIDOS.FX_ALTA)
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Sum
Devuelve la suma del conjunto de valores contenido en un campo especifico de
una consulta. Su sintaxis es:
SUM(<expr>)
En donde expr respresenta el nombre del campo que contiene los datos que
desean sumarse o una expresión que realiza un cálculo utilizando los datos de dichos
campos. Los operandos de expr pueden incluir el nombre de un campo de una tabla,
una constante o una función (la cual puede ser intrínseca o definida por el usuario
pero no otras de las funciones agregadas de SQL).
SELECT CLIENTES.NOMBRE,
SUM(PEDIDOS.TOTAL_PEDIDO)
FROM PEDIDOS
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
Podemos utilizar SELECT TOP con consultas agregadas como con cualquier otra
instruccion Transact SQL.
En este escenario es posible que queramos obtener los N valores que satisfagan
una condicion. Por ejemplo, queremos si queremos obtener los tres primeros clientes
con mayores pedidos, usariamos una consulta parecida a esta:
SELECT TOP 3
CLIENTES.NOMBRE,
SUM(DETALLE_PEDIDO.PRECIO)
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
INNER JOIN CLIENTES
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD)
Sin embargo, puede darse el caso, de que el cuarto cliente devuelto por la
consulta tenga un valor agragado identico al tercero, (es decir, estan empatados). El
uso de TOP 3 discriminaría el cuarto registro. Para evitar este comportamiento, y
que la consulta devuelva también al cuarto cliente utilizamos la clausula WITH TIES.
FROM DETALLE_PEDIDO
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD)
A partir de la version 2000 SQL Server incluye la clausula FOR XML para la
consultas. Sin embargo, es a partir de la versión 2005 cuando se integra XML como
tipo de dato nativo.
La clausula FOR XML admite los siguientes modos que representan el formato en
el que el XML es devuelto:
• XML AUTO, el modo AUTO emplea los campos en la
declaración SELECT para formar una jerarquía simple XML.
• XML RAW, el modo RAW genera elementos únicos, los cuales se
denominan row, por cada fila retornada.
• EXPLICIT, el modo EXPLICIT requiere un formato específico que puede ser
mapeado en casi cualquier forma XML, y al mismo tiempo ser formulado por
una sola consulta SQL.
FROM FAMILIAS
ORDER BY FAMILIA
FROM FAMILIAS
<FAMILIAS>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</FAMILIAS>
<FAMILIAS>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</FAMILIAS>
FROM FAMILIAS
ORDER BY FAMILIA
<row>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</row>
<row>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</row>
<row>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</row>
<row>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</row>
ORDER BY FAMILIA
FROM FAMILIAS
ORDER BY FAMILIA
<FamiliasDeProductos>
<CO_FAMILIA>1</CO_FAMILIA>
<FAMILIA>FAMILIA 1</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>2</CO_FAMILIA>
<FAMILIA>FAMILIA 2</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>3</CO_FAMILIA>
<FAMILIA>FAMILIA 3</FAMILIA>
</FamiliasDeProductos>
<FamiliasDeProductos>
<CO_FAMILIA>4</CO_FAMILIA>
<FAMILIA>FAMILIA 4</FAMILIA>
</FamiliasDeProductos>
SELECT
1 AS TAG, -- La primera columna debe tener el alias TAG
-- <NombreNodo>!<nodo>!<atributo>
CO_FAMILIA as "FamiliaDeProductos!1!CODIGO_FAMILIA",
FAMILIA as "FamiliaDeProductos!1!DESCRIPCION"
FROM FAMILIAS
ORDER BY FAMILIA
Dado que XML es un tipo nativo de XML podemos definir tablas con campos de tipo
XML, variables ...
GO
• Las consultas a unir deben tener el mismo número campos, y además los
campos deben ser del mismo tipo.
• Sólo puede haber una única clausula ORDER BY al final de la sentencia
SELECT.
UNION
FROM EMPLEADOS
UNION
FROM CLIENTES
FROM EMPLEADOS
UNION ALL
FROM CLIENTES
EXCEPT
FROM EMPLEADOS
EXCEPT
FROM CLIENTES
INTERSECT
FROM EMPLEADOS
INTERSECT
FROM CLIENTES
VALUES
(10, getdate(),getdate()+30, 1)
(PRECIO,
FX_INICIO,
FX_FIN,
CO_PRODUCTO)
SELECT PRECIO_UNIDAD,
getdate(),
getdate() + 30,
CO_PRODUCTO
FROM DETALLE_PEDIDO
También podemos forzar a que la insercción se realice con los datos por defecto
establecidos para la tabla (o null si no tienen valores por defecto).
VALUES
(10, getdate(),getdate()+30, 1)
PRINT @Codigo
VALUES
(10, getdate(),getdate()+30, 1)
PRINT @Codigo
Clausula OUTPUT
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instrucción UPDATE oDELETE. Es decir, son una copia de los datos "antes" del
cambio.
Las columnas con prefijo INSERTED reflejan el valor después de que se complete
la instrucción UPDATE oINSERT, pero antes de que se ejecuten los
desencadenadores. Es decir, son una copia de los datos "despues" del cambio.
( CO_PRECIO int,
PRECIO decimal,
FX_INICIO datetime,
FX_FIN datetime,
CO_PRODUCTO int
VALUES
(10, getdate(),getdate()+30, 1)
UPDATE <nombre_tabla>
SET <campo1> = <valor1>
{[,<campo2> = <valor2>,...,<campoN> = <valorN>]}
[ WHERE <condicion>];
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Sánchez'
WHERE CO_CLIENTE = 10
Un aspecto a tener en cuenta, sobre todo si has trabajado con ORACLE, es que
SQL graba los cambios inmediatamente sin necesidad de hacer COMMIT. Por
supuesto podemos gestionar nosostros las transacciones pero es algo que hay que
hacer de forma explicita con la instruccion BEGIN TRAN y que se verá en capitulos
posteriores de este tutorial.
En ocasiones queremos actaualizar los datos de una tabla con los datos de otra
(muy común para desnormalizar un modelo de datos).
UPDATE CLIENTES
SET
NOMBRE = FICHERO_CLIENTES.NOMBRE,
APELLIDO1 = FICHERO_CLIENTES.APELLIDO1,
APELLIDO2 = FICHERO_CLIENTES.APELLIDO2
FROM CLIENTES
ON FICHERO_CLIENTES.CO_CLIENTE = CLIENTES.CO_CLIENTE
Clausula OUTPUT
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instrucción UPDATE oDELETE. Es decir, son una copia de los datos "antes" del
cambio.
( CO_CLIENTE int ,
NOMBRE varchar(100),
APELLIDO1 varchar(100),
APELLIDO2 varchar(100)
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Sánchez'
Las columnas con prefijo INSERTED reflejan el valor después de que se complete
la instrucción UPDATE oINSERT, pero antes de que se ejecuten los
desencadenadores. Es decir, son una copia de los datos "despues" del cambio.
( CO_CLIENTE int ,
NOMBRE varchar(100),
APELLIDO1 varchar(100),
APELLIDO2 varchar(100)
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Sánchez'
Para ejecutar los ejemplos de este capitulo debemos ejecutar el siguiente script,
que crea la tabla "DATOS" y carga registros en ella.
dato varchar(100),
fx_alta datetime,
GO
DECLARE @i int,
@dato varchar(100)
set @i = 0
BEGIN
SET @i = @i +1
END
GO
SELECT * from DATOS
DELETE
FROM DATOS
DELETE
FROM DATOS
WHERE Id=12
Cuando borramos datos de una tabla, podemos obtener el número de filas que han
sido afectadas por la instrucción a través de la variable @@RowCount.
DELETE
FROM DATOS
WHERE Id=17
SELECT @@ROWCOUNT
Clausula OUTPUT
Id int,
dato varchar(100),
fx_alta datetime
DELETE
FROM DATOS
WHERE Id=17
Truncate Table
Cuando trabajamos con TRUNCATE TABLE debemos tener en cuenta las siguientes
consideraciones:
@CuentaOrigen VARCHAR(12),
@CuentaDestino VARCHAR(12)
*/
SET @importe = 50
UPDATE CUENTAS
SELECT
FROM CUENTAS
UPDATE CUENTAS
/* Registramos el movimiento */
SELECT
FROM CUENTAS
SET IMPLICIT_TRANSACTIONS ON
@CuentaOrigen VARCHAR(12),
@CuentaDestino VARCHAR(12)
*/
SET @importe = 50
BEGIN TRY
UPDATE CUENTAS
/* Registramos el movimiento */
SELECT
FROM CUENTAS
UPDATE CUENTAS
/* Registramos el movimiento */
SELECT
FROM CUENTAS
/* Confirmamos la transaccion*/
END TRY
BEGIN CATCH
END CATCH
SET IMPLICIT_TRANSACTIONS ON
@CuentaOrigen VARCHAR(12),
@CuentaDestino VARCHAR(12)
/* Asignamos el importe de la transferencia
*/
SET @importe = 50
BEGIN TRY
UPDATE CUENTAS
/* Registramos el movimiento */
SELECT
FROM CUENTAS
/* Registramos el movimiento */
SELECT
FROM CUENTAS
/* Confirmamos la transaccion*/
END TRY
BEGIN CATCH
END CATCH
SET IMPLICIT_TRANSACTIONS ON
BEGIN TRY
PRINT @@TRANCOUNT
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT 'Error'
END CATCH
Otro punto a tener en cuenta cuando trabajamos con transacciones son los
bloqueos y el nivel de aislamiento. Podemos aprender más sobre bloqueos y nivel de aislamiento
en este articulo.
Transacciones anidadas.
BEGIN TRAN
UPDATE EMPLEADOS
BEGIN TRAN
UPDATE EMPLEADOS
WHERE ID=101
COMMIT
ROLLBACK
BEGIN TRAN
UPDATE EMPLEADOS
SET NOMBRE = 'Devjoker'
WHERE ID=101
UPDATE EMPLEADOS
WHERE ID=101
UPDATE EMPLEADOS
WHERE ID=101
ROLLBACK TRANSACTION P1
-- Confirmamos la transaccion
COMMIT
AS
AS
@apellido1 varchar(100),
@apellido2 varchar(100),
@nifCif varchar(20),
@fxNaciento datetime
AS
@apellido1 varchar(100),
@apellido2 varchar(100),
@nifCif varchar(20),
@fxNaciento datetime
AS
BEGIN TRY
BEGIN TRAN
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT ERROR_MESSAGE()
END CATCH
AS
BEGIN
FROM CUENTAS
END
PRINT @saldo
AS
BEGIN
BEGIN
RETURN 1
END
ELSE
RETURN 0
END
PRINT @rv
AS
BEGIN
SELECT @numCuenta,
SALDO_ANTERIOR,
SALDO_POSTERIOR,
IMPORTE,
FXMOVIMIENTO
FROM MOVIMIENTOS
END
• Funciones escalares.
• Funciones en línea.
• Funciones en línea de multiples sentencias
Funciones escalares
Las funciones escalares devuelven un único valor de cualquier tipo de los datos tal
como int, money, varchar, real, etc.
-- Lista de parámetros
)
-- Tipo de datos que devuelve la función.
AS
BEGIN
...
END
@NumCuenta VARCHAR(20),
@Multiplicador DECIMAL(10,2)
RETURNS DECIMAL(10,2)
AS
BEGIN
DECLARE @Saldo DECIMAL(10,2),
@Return DECIMAL(10,2)
FROM CUENTAS
RETURN @Return
END
SELECT IDCUENTA,
NUMCUENTA,
SALDO,
FXALTA,
-- Ejecucion de la funcion:
FROM CUENTAS
@Resultado DECIMAL(10,2)
PRINT @Resultado
Funciones en linea
Las funciones en linea son las funciones que devuelven un conjunto de resultados
correspondientes a la eecución de una sentencia SELECT.
-- Lista de parámetros
RETURNS TABLE
AS
RETURN
@NumCuenta VARCHAR(20)
RETURNS TABLE
AS
RETURN
SELECT MOVIMIENTOS.*
FROM MOVIMIENTOS
Las funciones en linea pueden utilizarse dentro de joins o querys como si fueran
una tabla normal.
SELECT *
FROM CUENTAS
Este tipo de función se usa en situaciones donde se requiere una mayor lógica de
proceso.
-- Lista de parámetros
RETURNS
AS
BEGIN
END
* de estas cuentas
*/
NumCuenta varchar(20),
Saldo decimal(10,2),
Saldo_anterior decimal(10,2),
Saldo_posterior decimal(10,2),
Importe_Movimiento decimal(10,2),
FxMovimiento datetime
AS
BEGIN
@numcuenta varchar(20),
@saldo decimal(10,2)
FROM CUENTAS
OPEN CDATOS
-- Recorremos el cursor
WHILE (@@FETCH_STATUS = 0)
BEGIN
(NumCuenta, Saldo)
VALUES
(@numcuenta, @saldo)
(Saldo_anterior, Saldo_posterior,
Importe_Movimiento, FxMovimiento )
SELECT TOP 3
SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO
FROM MOVIMIENTOS
END
CLOSE CDATOS;
DEALLOCATE CDATOS;
RETURN
END
Cast y Convert
Donde:
SELECT @fecha
@fechaFormateada varchar(20)
-- 3 => dd/mm/aa
@dato2 int
SELECT @dato2
Evalua una expresion de entrado y si esta es NULL, reemplaza NULL con el valor
de reemplazo especificado. El valor de reemplazo debe ser del mismo tipo de datos
que la expresion a evaluar.
@datoVarchar varchar(100)
COALESCE
@dato2 int,
@dato3 int,
@dato4 int,
@dato5 int
-- Devuelve 100
SELECT COALESCE(@dato1,@dato2,@dato3,@dato4,@dato5)
GetDate y GetUTCDate
@fechaUTC datetime
Trigger DML.
Los trigger DML se ejecutan cuando un usuario intenta modificar datos mediante
un evento de lenguaje de manipulación de datos (DML). Los eventos DML son
instrucciones INSERT, UPDATE o DELETE de una tabla o vista.
AS
BEGIN
END
¿No existe una tabla UPDATED? No, hacer una actualización es lo mismo que
borrar (deleted) e insertar los nuevos (inserted). La sentencia UPDATE es la única
en la que inserted y deleted tienen datos simultaneamente.
ON CUENTAS
AFTER UPDATE
AS
BEGIN
FROM INSERTED
END
UPDATE CUENTAS
WHERE IDCUENTA = 1
Una consideración a tener en cuenta es que el trigger se ejecutará aunque la
instruccion DML (UPDATE, INSERT o DELETE ) no haya afectado a ninguna fila. En
este caso inserted y deleted devolveran un conjunto de datos vacio.
ON CUENTAS
AFTER UPDATE
AS
BEGIN
BEGIN
FROM INSERTED
END
END
Los trigger están dentro de la transacción original (Insert, Delete o Update) por lo
cual si dentro de nuestro trigger hacemos un RollBack Tran, no solo estaremos
echando atrás nuestro trigger sino también toda la transacción; en otras palabras si
en un trigger ponemos un RollBack Tran, la transacción de Insert, Delete o Update
volverá toda hacia atrás.
ALTER TRIGGER TR_CUENTAS
ON CUENTAS
AFTER UPDATE
AS
BEGIN
FROM INSERTED
ROLLBACK
END
GO
GO
Trigger DDL
ON DATABASE
AS
BEGIN
...
END
AS
BEGIN
ROLLBACK TRANSACTION
END
FOR
<sentencia_sql>
OPEN <nombre_cursor>
BEGIN
...
-- Cierra el cursor
CLOSE <nombre_cursor>
DEALLOCATE <nombre_cursor>
@Nombre varchar(255),
@Apellido1 varchar(255),
@Apellido2 varchar(255),
@NifCif varchar(20),
@FxNacimiento datetime
FROM CLIENTES
OPEN cClientes
WHILE (@@FETCH_STATUS = 0 )
BEGIN
END
CLOSE cClientes
DEALLOCATE cClientes
Valor
Descripción
devuelto
0 La instrucción FETCH se ejecutó correctamente.
La instrucción FETCH no se ejecutó correctamente o la fila estaba más allá
-1
del conjunto de resultados.
-2 Falta la fila recuperada.
[ LOCAL | GLOBAL ]
[ FORWARD_ONLY | SCROLL ]
[ TYPE_WARNING ]
FOR <sentencia_sql>
• LOCAL
Especifica que el ámbito del cursor es local para el proceso por lotes,
procedimiento almacenado o desencadenador en que se creó el cursor.
FROM CLIENTES
• GLOBAL
Especifica que el ámbito del cursor es global para la conexión. Puede hacerse
referencia al nombre del cursor en cualquier procedimiento almacenado o
proceso por lotes que se ejecute en la conexión.
FROM CLIENTES
Si no se especifica GLOBAL ni LOCAL, el valor predeterminado se controla
mediante la configuración de la opción de base de datos default to local cursor.
• FORWARD_ONLY
Especifica que el cursor sólo se puede desplazar de la primera a la última fila.
FETCH NEXT es la única opción de recuperación admitida.
FROM CLIENTES
• SCROLL
Especifica que están disponibles todas las opciones de recuperación (FIRST,
LAST, PRIOR, NEXT, RELATIVE, ABSOLUTE). Si no se especifica SCROLL en una
instrucción DECLARE CURSOR la única opción de recuperación que se admite
es NEXT. No es posible especificar SCROLL si se incluye también
FAST_FORWARD.
Si se incluye la opción SCROLL, la forma en la realizamos la lectura del cursor
varia, debiendo utilizar la siguiente sintaxis: FETCH [ NEXT | PRIOR | FIRST |
LAST | RELATIVE | ABSOLUTE ] FROM < INTO
@Nombre varchar(255),
@Apellido1 varchar(255),
@Apellido2 varchar(255),
@NifCif varchar(20),
@FxNacimiento datetime
-- Declaración del cursor
FROM CLIENTES
OPEN cClientes
WHILE (@@FETCH_STATUS = 0 )
BEGIN
INTO @id,@Nombre,@Apellido1,@Apellido2,@NifCif,@FxNacimiento
END
DEALLOCATE cClientes
• STATIC
Define un cursor que hace una copia temporal de los datos que va a utilizar.
Todas las solicitudes que se realizan al cursor se responden desde esta tabla
temporal de tempdb; por tanto, las modificaciones realizadas en las tablas
base no se reflejan en los datos devueltos por las operaciones de
recuperación realizadas en el cursor y además este cursor no admite
modificaciones.
FROM CLIENTES
• KEYSET
Especifica que la pertenencia y el orden de las filas del cursor se fijan cuando
se abre el cursor. El conjunto de claves que identifica las filas de forma única
está integrado en la tabla denominada keyset de tempdb.
FROM CLIENTES
• DYNAMIC
Define un cursor que, al desplazarse por él, refleja en su conjunto de
resultados todos los cambios realizados en los datos de las filas. Los valores
de los datos, el orden y la pertenencia de las filas pueden cambiar en cada
operación de recuperación. La opción de recuperación ABSOLUTE no se puede
utilizar en los cursores dinámicos.
FROM CLIENTES
• FAST_FORWARD
Especifica un cursor FORWARD_ONLY, READ_ONLY con las optimizaciones de
rendimiento habilitadas. No se puede especificar FAST_FORWARD si se
especifica también SCROLL o FOR_UPDATE.
FROM CLIENTES
• READ_ONLY
Evita que se efectúen actualizaciones a través de este cursor. No es posible
hacer referencia al cursor en una cláusula WHERE CURRENT OF de una
instrucción UPDATE o DELETE. Esta opción reemplaza la capacidad de
actualizar el cursor.
FROM CLIENTES
• SCROLL_LOCKS
Especifica que se garantiza que las actualizaciones o eliminaciones
posicionadas realizadas a través del cursor serán correctas. Microsoft SQL
Server bloquea las filas cuando se leen en el cursor para garantizar que
estarán disponibles para futuras modificaciones. No es posible especificar
SCROLL_LOCKS si se especifica también FAST_FORWARD o STATIC.
FROM CLIENTES
• OPTIMISTIC
Especifica que las actualizaciones o eliminaciones posicionadas realizadas a
través del cursor no se realizarán correctamente si la fila se ha actualizado
después de ser leída en el cursor. SQL Server no bloquea las filas al leerlas en
el cursor. En su lugar, utiliza comparaciones de valores de columna timestamp
o un valor de suma de comprobación si la tabla no tiene columnas timestamp,
para determinar si la fila se ha modificado después de leerla en el cursor. Si la
fila se ha modificado, el intento de actualización o eliminación posicionada
genera un error. No es posible especificar OPTIMISTIC si se especifica también
FAST_FORWARD.
FROM CLIENTES
• TYPE_WARNING
Especifica que se envía un mensaje de advertencia al cliente si el cursor se
convierte implícitamente del tipo solicitado a otro.
DECLARE cClientes CURSOR TYPE_WARNING FOR
FROM CLIENTES
FROM CLIENTES
Para actualizar los datos de un cursor debemos especificar FOR UPDATE despues
de la sentencia SELECT en la declaración del cursor, y WHERE CURRENT OF
<nombre_cursor> en la sentencia UPDATE tal y como muestra el siguiente ejemplo.
@Nombre varchar(255),
@Apellido1 varchar(255),
@Apellido2 varchar(255),
@NifCif varchar(20),
@FxNacimiento datetime
FROM CLIENTES
FOR UPDATE
OPEN cClientes
FETCH cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento
WHILE (@@FETCH_STATUS = 0 )
BEGIN
UPDATE Clientes
FETCH cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2,
@NifCif, @FxNacimiento
END
CLOSE cClientes
DEALLOCATE cClientes
La instrucción EXECUTE
COD_PAIS,
NOMBRE_PAIS,
ACTIVO,
FX_ALTA
FROM
PAISES'
EXEC (@sql)
También con SQL dinamico podemos ejecutar sentencias de tipo DDL (Data
Definition Languaje), como CREATE TABLE.
EXEC (@sql)
EXEC (@sql)
COD_PAIS,
NOMBRE_PAIS,
ACTIVO,
FX_ALTA
FROM
PAISES'
@paramDefinition nvarchar(255),
@paramValue char(3)
COD_PAIS,
NOMBRE_PAIS,
ACTIVO,
FX_ALTA
FROM
PAISES