Académique Documents
Professionnel Documents
Culture Documents
Transact SQL existe desde las primeras versiones de SQL Server, si bien a lo
largo de este tutorial nos centraremos en la versin SQL Server 2005.
Que vamos a necesitar?
Para poder seguir este tutorial correctamente necesitaremos tener los siguientes
elementos:
Procedimientos almacenados
Funciones
Triggers
Scripts
Pero adems Transact SQL nos permite realizar programas sobre las siguientes
herramientas de SQL Server:
Service Broker
Scripts y lotes.
Un script de Transact SQL es un conjunto de sentencias de Transact
en formato de texto plano que se ejecutan en un servidor de SQL Server.
SQL
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 travs de las instruccin GO.
Bit. Una columna o variable de tipo bit puede almacenar el rango de valores de 1
a 0.
Tinyint. Una columna o variable de tipo tinyint puede almacenar el rango de
valores de 0 a 255.
SmallInt. Una columna o variable de tipo smallint puede almacenar el rango de
valores -32768 a 32767.
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 .
Decimal(p,s). Una columna de tipo decimal puede almacenar datos nmericos
decimales sin redondear. Donde p es la precision (nmero total del dgitos) y s la
escala (nmero de valores decimales)
Float. Una columna de datos float puede almacenar el rango de valores -1,79x10308 a 1,79x-10308, , si la definimos con el valor mxmo de precisin. La precisin
puede variar entre 1 y 53.
Real. Sinnimo de float(24). Puede almacenar el rango de valores -3,4x-10 38 a 3,4x1038,
Money. Almacena valores nmericos monetarios de -263 a 263-1, con una precisin
de hasta diexz milesimas de la unidad monetaria.
SmallMoney. Almacena valores nmericos monetarios de -214.748,3647 a
214.748,3647, con una precisin de hasta diez milesimas de la unidad monetaria.
Todos los tipos de datos enteros pueden marcarse con la propiedad identity para
hacerlos autonumricos.
print @money
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.
<row nombre="SVR01"/>
variables en Transact SQL debemos utilizar la palabra clave declare, seguido del
identificador y tipo de datos de la variable.
(SELECT nombre
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
OPEN CDATOS
FETCH CDATOS INTO @nombre, @apellido1, @apellido2
WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT @nombre
PRINT @apellido1
PRINT @apellido2
FETCH CDATOS INTO @nombre, @apellido1, @apellido2
END
CLOSE CDATOS
DEALLOCATE CDATOS
SQL Server
varbinary
SqlBytes, SqlBinary
Byte[]
binary
SqlBytes, SqlBinary
Byte[]
varbinary(1),
binary(1)
SqlBytes, SqlBinary
byte, Byte[]
image
ninguno
ninguno
varchar
ninguno
ninguno
char
ninguno
ninguno
nvarchar(1),
nchar(1)
SqlChars, SqlString
SqlChars, SqlString
nvarchar
String, Char[]
SQLChars es mejor para la transferencia de
datos y SQLString obtiene mejor rendimiento
para operaciones con Strings.
nchar
SqlChars, SqlString
String, Char[]
text
ninguno
ninguno
ntext
ninguno
ninguno
uniqueidentifier SqlGuid
Guid
rowversion
ninguno
Byte[]
bit
SqlBoolean
Boolean
tinyint
SqlByte
Byte
smallint
SqlInt16
Int16
int
SqlInt32
Int32
bigint
SqlInt64
Int64
smallmoney
SqlMoney
Decimal
money
SqlMoney
Decimal
numeric
SqlDecimal
Decimal
decimal
SqlDecimal
Decimal
real
SqlSingle
Single
float
SqlDouble
Double
smalldatetime
SqlDateTime
DateTime
datetime
SqlDateTime
DateTime
sql_variant
ninguno
Object
User-defined
type(UDT)
ninguno
table
ninguno
ninguno
cursor
ninguno
ninguno
timestamp
ninguno
ninguno
xml
SqlXml
ninguno
Tipo de operador
Operadores
Operador de
asignacin
Operadores
aritmticos
Operadores
relacionales o de
comparacin
Operadores lgicos
Operador de
concatenacin
+ (suma)
- (resta)
* (multiplicacin)
/ (divisin)
** (exponente)
% (modulo)
= (igual a)
<> (distinto de)
!= (distinto de)
< (menor que)
> (mayor que)
>= (mayor o igual a)
<= (menor o igual a)
!> (no mayor a)
!< (no menor a)
AND (y lgico)
NOT (negacion)
OR (o lgico)
& (AND a nivel de bit)
|
(OR a nivel de bit)
^
(OR exclusivo a nivel de bit)
+
ALL (Devuelve TRUE si el conjunto completo de comparaciones es TRUE)
ANY(Devuelve TRUE si cualquier elemento del conjunto de comparaciones
es TRUE)
Otros
IF (<expresion>)
BEGIN
...
END
ELSE IF (<expresion>)
BEGIN
...
END
ELSE
BEGIN
...
END
Ejemplo de la estructura condicional IF.
@diminutivo = 'DJK'
BEGIN
PRINT 'www.devjoker.com'
END
ELSE
BEGIN
PRINT 'Otra Web (peor!)'
END
La estructura IF admite el uso de subconsultas:
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
END
El mismo ejemplo aplicando esta sintaxis:
PRINT @Web
END)
PRINT @Web
END)
Bucle WHILE
El bucle WHILE se repite mientras expresion se evalue como verdadero.
Es el nico tipo de bucle del que dispone Transact SQL.
WHILE <expresion>
BEGIN
...
END
Un ejemplo del bucle WHILE.
SET @contador = 0
WHILE (1 = 1)
BEGIN
SET @contador = @contador + 1
IF (@contador % 50 = 0)
BREAK
PRINT 'Iteracion del bucle ' + cast(@contador AS varchar)
END
Tambin podemos utilizar el bucle WHILE conuntamente con subconsultas.
Estructura GOTO
La sentencia goto nos permite desviar el flujo de ejecucin hacia una etiqueta.
Fu muy utilizada en versiones anteriores de SQL Server conjuntamente con la
variable de sistema @@ERROR para el control de errores.
Actualmente, se desaconseja el uso GOTO, recomendandose el uso de TRY CATCH para la gestion de errores.
BEGIN TRY
...
END TRY
BEGIN CATCH
...
END CATCH
El siguiente ejemplo ilustra el uso de TRY - CATCH.
BEGIN TRY
DECLARE @divisor int ,
@dividendo int,
@resultado int
SET @dividendo = 100
SET @divisor = 0
-- Esta linea provoca un error de division por 0
SET @resultado = @dividendo/@divisor
PRINT 'No hay error'
END TRY
BEGIN CATCH
PRINT 'Se ha producido un error'
END CATCH
BEGIN TRY
DECLARE @divisor int ,
@dividendo int,
@resultado int
SET @dividendo = 100
SET @divisor = 0
-- Esta linea provoca un error de division por 0
SET @resultado = @dividendo/@divisor
PRINT 'No hay error'
END TRY
BEGIN CATCH
PRINT ERROR_NUMBER()
PRINT ERROR_SEVERITY()
PRINT ERROR_STATE()
PRINT ERROR_PROCEDURE()
PRINT ERROR_LINE()
PRINT ERROR_MESSAGE()
END CATCH
Lgicamente, podemos utilizar estas funciones para almacenar esta informacin
en una tabla de la base de datos y registrar todos los errores que se produzcan.
DECLARE @divisor
int ,
@dividendo int ,
@resultado int
SET @dividendo = 100
SET @divisor = 0
-- Esta linea provoca un error de division por 0
SET @resultado = @dividendo/@divisor
IF @@ERROR = 0
BEGIN
PRINT 'No hay error'
END
ELSE
BEGIN
PRINT 'Hay error'
END
DECLARE @divisor
int ,
@dividendo int ,
@resultado int
SET @dividendo = 100
SET @divisor = 0
-- Esta linea provoca un error de division por 0
SET @resultado = @dividendo/@divisor
PRINT 'Controlando el error ...' -- Esta linea estable @@ERROR a cero
IF @@ERROR = 0
BEGIN
-- Se ejecuta esta parte!
PRINT 'No hay error'
END
ELSE
BEGIN
PRINT 'Hay error'
END
El siguiente ejemplo muestra una consulta sencilla que obtiene el cdigo y la "familia" de
una tabla llamada familias (representara familias de productos por ejemplo).
El uso del asterisco indica que queremos que la consulta devuelva todos los campos que
existen en la tabla.
SELECT *
FROM FAMILIAS
Ahora vamos a realizar una consulta obteniendo adems de los datos de familias, los datos
de las categorias y los productos.
SELECT *
FROM FAMILIAS
INNER JOIN CATEGORIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
INNER JOIN PRODUCTOS
ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA
SELECT *
FROM FAMILIAS
LEFT OUTER JOIN CATEGORIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
LEFT OUTER JOIN PRODUCTOS
ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA
Los registros que no tengan datos relacionados en una consulta LEFT JOIN devolveran en
valor null en los campos que correspondan a las tablas en las que no tienen dato.
Tambin podemos forzar un producto cartesiano (todos con todos) a travs de CROSS
JOIN.
La clusula WHERE
La clusula WHERE es la instruccin que nos permite filtrar el resultado de una sentencia
SELECT.
SELECT *
FROM FAMILIAS
WHERE CO_FAMILIA = 1
OR CO_FAMILIA = 2
SELECT *
FROM FAMILIAS
WHERE CO_FAMILIA IN ( 1 , 2)
La clausula WHERE se puede utilizar conjuntamente con INNER JOIN, LEFT JOIN ...
SELECT
FAMILIAS.CO_FAMILIA,
FAMILIAS.FAMILIA
FROM FAMILIAS
INNER JOIN CATEGORIAS
ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA
WHERE FAMILIAS.CO_FAMILIA > 1
SELECT *
FROM FAMILIAS
WHERE FAMILIA = 'FAMILIA 1'
SELECT *
FROM FAMILIAS
WHERE FAMILIA LIKE 'FAM%'
_ , representa un caracter.
La clusula ORDER BY
Podemos especificar el orden en el que sern devueltos los datos a travs de la clusula
ORDER BY.
Tambin podemos indicar el ndice del campo en la lista de seleccin en lugar de su nombre :
FROM FAMILIAS
ORDER BY 2 DESC -- Ordena por FAMILIA
Consultas agregadas
La clusula GROUP BY
La clausula GROUP BY combina los registros devueltos por una consulta SELECT
obteniendo uno o varios valores agregados(suma, valor mnimo y mximo ...).
Para cada registro se puede crear un valor agregado si se incluye una funcin SQL
agregada, como por ejemplo Sum o Count, en la instruccin 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,
SUM(PRECIO) -- Total del pedido
FROM DETALLE_PEDIDO
INNER JOIN PEDIDOS
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
INNER JOIN CLIENTES
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
INNER JOIN PEDIDOS
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
INNER JOIN CLIENTES
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
-- La clausula WHERE se aplica antes de realizar el calculo
La clusula HAVING
Es posible que necesitemos calcular un agregado, pero que no necesitemos obtener todos
los datos, solo los que cumplan una condicin del agregado. Por ejemplo, podemos calcular el
valor de las ventas por producto, pero que solo queramos ver los datos de los producto que
hayan vendido ms o menos de una determinada cantidad. En estos casos debemos utilizar la
clausula HAVING.
Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier registro
agrupado por la clusula GROUP BY que satisfaga las condiciones de la clusula HAVING. Se
utiliza la clusula WHERE para excluir aquellas filas que no desea agrupar, y la clusula
HAVING para filtrar los registros una vez agrupados.
HAVING es similar a WHERE, determina qu registros se seleccionan pero despues de
calcular el agregado. Una vez que los registros se han agrupado utilizando GROUP BY,
HAVING determina cuales de ellos se van a mostrar. HAVING permite el uso de funciones
agregadas.
SELECT
CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
SUM(PRECIO) -- Total del pedido
FROM DETALLE_PEDIDO
INNER JOIN PEDIDOS
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
INNER JOIN CLIENTES
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
-- La clausula WHERE se aplica antes de realizar el calculo
WHERE CLIENTES.NOMBRE != 'UN NOMBRE'
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
HAVING SUM(PRECIO) > 100
Funciones agregadas.
Transact SQL pone a nuestra disposicin multiples funciones agregadas, las ms comunes
son:
MAX
MIN
COUNT
SUM
AVG
AVG
Calcula la media aritmtica de un conjunto de valores contenidos en un campo
especificado de una consulta. Su sintaxis es la siguiente
AVG(<expr>)
En donde expr representa el campo que contiene los datos numricos para los que se desea
calcular la media o una expresin que realiza un clculo utilizando los datos de dicho campo.
La media calculada por Avg es la media aritmtica (la suma de los valores dividido por el
nmero de valores). La funcin Avg no incluye ningn campo Null en el clculo.
SELECT
CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2,
AVG(PRECIO) -- Promedio del pedido
FROM DETALLE_PEDIDO
INNER JOIN PEDIDOS
ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO
INNER JOIN CLIENTES
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE,
CLIENTES.APELLIDO1,
CLIENTES.APELLIDO2
Count
Calcula el nmero de registros devueltos por una consulta. Su sintaxis es la siguiente:
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 funcin (la cual
puede ser intrnseca o definida por el usuario pero no otras de las funciones agregadas de
SQL). Puede contar cualquier tipo de datos incluso texto.
Aunque expr puede realizar un clculo sobre un campo, Count simplemente cuenta el
nmero de registros sin tener en cuenta qu valores se almacenan en los registros. La funcin
Count no cuenta los registros que tienen campos null a menos que expr sea el carcter
comodn asterisco (*). Si utiliza un asterisco, Count calcula el nmero total de registros,
incluyendo aquellos que contienen campos null. Count(*) es considerablemente ms rpida
que Count(Campo).
SELECT COUNT(*)
FROM PEDIDOS
Max, Min
Devuelven el mnimo o el mximo de un conjunto de valores contenidos en un campo
especifico de una consulta. Su sintaxis es:
MIN(<expr>)
MAX(<expr>)
En donde expr es el campo sobre el que se desea realizar el clculo. Expr pueden incluir el
nombre de un campo de una tabla, una constante o una funcin (la cual puede ser intrnseca
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
INNER JOIN CLIENTES
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 expresin que realiza un clculo utilizando los datos de dichos campos. Los
operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una
funcin (la cual puede ser intrnseca o definida por el usuario pero no otras de las funciones
agregadas de SQL).
SELECT
CLIENTES.NOMBRE,
SUM(PEDIDOS.TOTAL_PEDIDO)
FROM PEDIDOS
INNER JOIN CLIENTES
ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE
GROUP BY CLIENTES.NOMBRE
SELECT TOP 3
CLIENTES.NOMBRE,
SUM(DETALLE_PEDIDO.PRECIO)
FROM DETALLE_PEDIDO
INNER JOIN PEDIDOS
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
discriminara el cuarto registro. Para evitar este comportamiento, y que la consulta devuelva
tambin al cuarto cliente utilizamos la clausula WITH TIES.
XML RAW, el modo RAW genera elementos nicos, los cuales se denominan
row, por cada fila retornada.
<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>
<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>
<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,
as "FamiliaDeProductos!1!DESCRIPCION"
FROM FAMILIAS
ORDER BY FAMILIA
FOR XML EXPLICIT
GO
Las consultas a unir deben tener el mismo nmero campos, y adems los
campos deben ser del mismo tipo.
UNION
UNION devuelve la suma de dos o ms conjuntos de resultados. El conjunto
obtenido como resultado de UNION tiene la misma estructura que los conjuntos
originales.
El siguiente ejemplo muestra el uso de UNION
EXCEPT
EXCEPT devuelve la diferencia (resta) de dos o ms conjuntos de resultados. El
conjunto obtenido como resultado de EXCEPT tiene la misma estructura que los
conjuntos originales.
El siguiente ejemplo muestra el uso de EXCEPT
INTERSECT
Devuelve la interseccin entre dos o ms conjuntos de resultados en uno. El
conjunto obtenido como resultado de INTERSECT tiene la misma estructura que los
conjuntos originales.
El siguiente ejemplo muestra el uso de INTERSECT
Tambin es posible insertar en una tabla el resultado de una consulta SELECT. De este
modo se insertarn tantas filas como haya devuelto la consulta SELECT.
El siguiente ejemplo muestra la insercin multiple de filas.
PRECIO_UNIDAD,
getdate(),
getdate() + 30,
CO_PRODUCTO
FROM DETALLE_PEDIDO
En SQL Sever podemos marcar un campo de una tabla como autonumrico (identity),
cuando insertamos un registro en dicha tabla el valor del campo se genera automaticamente.
Para recuperar el valor generado disponemos de varios mtodos:
Utilizar la funcion @@identity, que devuelve el ltimo valor identidad insertado por la
transaccion:
PRINT @Codigo
Clausula OUTPUT
A partir de la version de SQL Server 2005 disponemos de la clausula OUTPUT para
recuperar los valores que hemos insertado. Al igual que en un trigger disponemos de las
tablas lgicas INSERTED y DELETED.
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del cambio.
DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT.
Las columnas con prefijo INSERTED reflejan el valor despus de que se complete la
instruccin UPDATE o INSERT, pero antes de que se ejecuten los desencadenadores. Es
decir, son una copia de los datos "despues" del cambio.
UPDATE <nombre_tabla>
SET <campo1> = <valor1>
{[,<campo2> = <valor2>,...,<campoN> = <valorN>]}
[ WHERE <condicion>];
El siguiente ejemplo muestra el uso de UPDATE.
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Snchez'
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.
UPDATE CLIENTES
SET
NOMBRE = FICHERO_CLIENTES.NOMBRE,
APELLIDO1 = FICHERO_CLIENTES.APELLIDO1,
APELLIDO2 = FICHERO_CLIENTES.APELLIDO2
FROM CLIENTES
INNER JOIN FICHERO_CLIENTES
ON FICHERO_CLIENTES.CO_CLIENTE = CLIENTES.CO_CLIENTE
Clausula OUTPUT
A partir de la version de SQL Server 2005 disponemos de la clausula OUTPUT
para recuperar los valores que hemos insertado. Al igual que en un trigger
disponemos de las tablas lgicas INSERTED y DELETED.
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del
cambio.
DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT.
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Snchez'
OUTPUT
Las columnas con prefijo INSERTED reflejan el valor despus de que se complete
la instruccin UPDATE o INSERT, pero antes de que se ejecuten los
desencadenadores. Es decir, son una copia de los datos "despues" del cambio.
INSERTED no se puede utilizar con la clusula OUTPUT en la instruccin
DELETE.
APELLIDO1 varchar(100),
APELLIDO2 varchar(100)
)
UPDATE CLIENTES
SET
NOMBRE = 'Devjoker',
APELLIDO1 = 'Herrarte',
APELLIDO2 = 'Snchez'
OUTPUT
GO
DECLARE @i int,
@dato varchar(100)
set @i = 0
WHILE (@i <100)
BEGIN
SET @i = @i +1
set @dato = 'Dato:' + cast(@i as varchar)
INSERT INTO DATOS (dato, fx_alta)
VALUES (@dato, getdate())
END
GO
DELETE
FROM DATOS
DELETE
FROM DATOS
WHERE Id=12
Cuando borramos datos de una tabla, podemos obtener el nmero de filas que
han sido afectadas por la instruccin a travs de la variable @@RowCount.
El siguiente ejemplo ilustra el uso de @@RowCount.
DELETE
FROM DATOS
WHERE Id=17
SELECT @@ROWCOUNT
Clausula OUTPUT
A partir de la version de SQL Server 2005 disponemos de la clausula OUTPUT
para recuperar los valores que hemos insertado. Al igual que en un trigger
disponemos de las tablas lgicas INSERTED y DELETED.
Las columnas con prefijo DELETED reflejan el valor antes de que se complete la
instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del
cambio.
DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT.
DELETE
FROM DATOS
OUTPUT DELETED.* INTO @FILAS_BORRADAS
WHERE Id=17
Truncate Table
Para borrar datos de forma masiva disponemos de la instruccin TRUNCATE
TABLE, que borra todos los datos de una tabla.
= '200700000001'
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR, IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO + @importe, SALDO, @importe, getdate()
FROM CUENTAS
WHERE NUMCUENTA = @CuentaOrigen
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR, IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO - @importe, SALDO, @importe, getdate()
FROM CUENTAS
WHERE NUMCUENTA = @CuentaDestino
Transacciones explcitas
Cada transaccin se inicia explcitamente con la instruccin BEGIN TRANSACTION y
se termina explcitamente con una instruccin COMMIT o ROLLBACK.
Transacciones implcitas
Se inicia automtivamente una nueva transaccin cuando se ejecuta una
instruccin que realiza modificaciones en los datos, pero cada transaccin se
completa explcitamente con una instruccin COMMIT o ROLLBACK.
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO + @importe, SALDO, @importe, getdate()
FROM CUENTAS
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO - @importe, SALDO, @importe, getdate()
FROM CUENTAS
WHERE NUMCUENTA = @CuentaDestino
/* Confirmamos la transaccion*/
COMMIT TRANSACTION -- O solo COMMIT
END TRY
BEGIN CATCH
/* Hay un error, deshacemos los cambios*/
ROLLBACK TRANSACTION -- O solo ROLLBACK
PRINT 'Se ha producido un error!'
END CATCH
SET IMPLICIT_TRANSACTIONS ON
BEGIN TRY
/* Descontamos el importe de la cuenta origen */
UPDATE CUENTAS
SET SALDO = SALDO - @importe
WHERE NUMCUENTA = @CuentaOrigen
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO + @importe, SALDO, @importe, getdate()
FROM CUENTAS
/* Registramos el movimiento */
INSERT INTO MOVIMIENTOS
(IDCUENTA, SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO)
SELECT
IDCUENTA, SALDO - @importe, SALDO, @importe, getdate()
FROM CUENTAS
WHERE NUMCUENTA = @CuentaDestino
/* Confirmamos la transaccion*/
COMMIT TRANSACTION -- O solo COMMIT
END TRY
BEGIN CATCH
/* Hay un error, deshacemos los cambios*/
ROLLBACK TRANSACTION -- O solo ROLLBACK
PRINT 'Se ha producido un error!'
END CATCH
SET IMPLICIT_TRANSACTIONS ON
BEGIN TRY
UPDATE CUENTAS SET FXALTA = FXALTA - 1
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 ms sobre bloqueos y nivel de
aislamiento en este articulo.
Transacciones anidadas.
Podemos anidar varias transacciones. Cuando anidamos varias transacciones la
instruccin COMMIT afectar a la ltima transaccin abierta, pero ROLLBACK
afectar a todas las transacciones abiertas.
Un hecho a tener en cuenta, es que, si hacemos ROLLBACK de la transaccin
superior se desharan tambin los cambios de todas las transacciones internas,
aunque hayamos realizado COMMIT de ellas.
BEGIN TRAN
UPDATE EMPLEADOS
SET NOMBRE = 'Devjoker'
WHERE ID=101
BEGIN TRAN
UPDATE EMPLEADOS
SET APELLIDO1 = 'Devjoker.COM'
WHERE ID=101
BEGIN TRAN
UPDATE EMPLEADOS
SET NOMBRE = 'Devjoker'
WHERE ID=101
UPDATE EMPLEADOS
SET APELLIDO1 = 'Devjoker.COM'
WHERE ID=101
UPDATE EMPLEADOS
SET APELLIDO1 = 'Otra cosa!'
WHERE ID=101
-- Confirmamos la transaccion
COMMIT
AS
-- Sentencias del procedure
@nombre varchar(100),
@apellido1 varchar(100),
@apellido2 varchar(100),
@nifCif varchar(20),
@fxNaciento datetime
AS
BEGIN TRY
BEGIN TRAN
INSERT INTO CLIENTES
(nombre, apellido1, apellido2, nifcif, fxnacimiento) VALUES
(@nombre, @apellido1, @apellido2, @nifCif, @fxNaciento)
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT ERROR_MESSAGE()
END CATCH
@numCuenta,
SALDO_ANTERIOR,
SALDO_POSTERIOR,
IMPORTE,
FXMOVIMIENTO
FROM MOVIMIENTOS
20070000000150.99100.9950.0020070825
16:18:36.490
2007000000010.9950.9950.0020070823
16:20:41.183
20070000000150.990.9950.0020070823
16:16:29.840
2007000000010.9950.9950.0020070823
16:14:05.900
Funciones escalares.
Funciones en lnea.
Funciones escalares
Las funciones escalares devuelven un nico valor de cualquier tipo de los datos
tal como int, money, varchar, real, etc.
La sintaxis para una funcin escalar es la siguiente:
RETURN @Return
END
SELECT
IDCUENTA,
NUMCUENTA,
SALDO,
FXALTA,
-- Ejecucion de la funcion:
PRINT @Resultado
Funciones en linea
Las funciones en linea son las funciones que devuelven un conjunto de resultados
correspondientes a la eecucin de una sentencia SELECT.
La sintaxis para una funcin de tabla en linea es la siguiente:
@NumCuenta VARCHAR(20)
)
RETURNS TABLE
AS
RETURN
(
SELECT MOVIMIENTOS.*
FROM MOVIMIENTOS
INNER JOIN CUENTAS ON MOVIMIENTOS.IDCUENTA = CUENTAS.IDCUENTA
WHERE CUENTAS.NUMCUENTA = @NumCuenta
)
SELECT *
FROM CUENTAS
INNER JOIN CUENTAS_CLIENTE
ON CUENTAS_CLIENTE.IDCUENTA = CUENTAS.IDCUENTA
INNER JOIN CLIENTES
ON CLIENTES.id = CUENTAS_CLIENTE.IDCLIENTE
INNER JOIN fn_MovimientosCuenta('200700000001') A
ON A.IDCUENTA= CUENTAS.IDCUENTA
Este tipo de funcin se usa en situaciones donde se requiere una mayor lgica de
proceso.
La sintaxis para una funciones de tabla de multi sentencias es la siguiente:
*/
OPEN CDATOS
FETCH CDATOS INTO @idcuenta, @numcuenta, @saldo
-- Recorremos el cursor
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Insertamos la cuenta en la variable de salida
INSERT INTO @datos
(NumCuenta, Saldo)
VALUES
(@numcuenta, @saldo)
-- Insertamos los tres ltimos movimientos de la cuenta
INSERT INTO @datos
(Saldo_anterior, Saldo_posterior,
Importe_Movimiento, FxMovimiento )
SELECT TOP 3
SALDO_ANTERIOR, SALDO_POSTERIOR,
IMPORTE, FXMOVIMIENTO
FROM MOVIMIENTOS
WHERE IDCUENTA = @idcuenta
ORDER BY FXMOVIMIENTO DESC
-- Vamos a la siguiente cuenta
FETCH CDATOS INTO @idcuenta, @numcuenta, @saldo
END
CLOSE CDATOS;
DEALLOCATE CDATOS;
RETURN
END
Saldo_posterior
Importe_Movimiento
---------------- ------------------NULL
NULL
500.00
50.00
2007-08-25
550.00
50.00
2007-08-23
550.00
50.00
2007-08-23
NULL
NULL
100.99
50.00
2007-08-25
50.99
50.00
2007-08-23
0.99
50.00
2007-08-23
Cast y Convert
Convierten una expresin de un tipo de datos en otro de forma explcita. CAST y
CONVERT proporcionan funciones similares.
CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
Donde:
style, parametro opcional que especifica el formato que tiene expresion. Por
ejemplo, si queremos convertir un varchar a datetime, aqui debemos
especificar el formato de la fecha (el tipo varchar).
SELECT @fecha
SELECT @fechaFormateada
SELECT @dato2
Con el siglo ?
(aaaa)
Estndar
Entrada/salida (3)
0 o 100 (1, 2)
Valor predeterminado
101
EE.UU.
mm/dd/aaaa
102
ANSI
aa.mm.dd
103
Britnico/Francs
dd/mm/aa
104
Alemn
dd.mm.aa
105
Italiano
dd-mm-aa
106
(1)
dd mes aa
107
(1)
Mes dd, aa
108
hh:mi:ss
9 o 109 (1, 2)
Valor predeterminado +
milisegundos
mes dd aaaa
hh:mi:ss:mmma.m. (o p. m.)
10
110
EE.UU.
mm-dd-aa
11
111
JAPN
aa/mm/dd
12
112
ISO
aammdd
13 o 113 (1, 2)
Europeo predeterminado +
milisegundos
dd mes aaaa
hh:mi:ss:mmm(24h)
14
114
hh:mi:ss:mmm(24h)
20 o 120 (2)
ODBC cannico
aaaa-mm-dd hh:mi:ss(24h)
21 o 121 (2)
aaaa-mm-dd
hh:mi:ss.mmm(24h)
126 (4)
ISO8601
aaaa-mm-ddThh:mi:ss.mmm
(sin espacios)
127(6, 7)
aaaa-mm-ddThh:mi:ss.mmmZ
(sin espacios)
130 (1, 2)
Hijri (5)
dd mes aaaa
hh:mi:ss:mmma.m.
131 (2)
Hijri (5)
dd/mm/aa hh:mi:ss:mmma.m.
Isnull
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.
ISNULL ( expression , replacement_value )
SELECT
ISNULL(@dato, -1),
ISNULL(@datoVarchar, 'No hay dato')
COALESCE
Devuelve la primera expresin distinta de NULL entre sus argumentos. Un
aspecto a tener en cuenta es que todos los argumentos deben ser del mismo tipo.
-- Devuelve 100
SELECT COALESCE(@dato1,@dato2,@dato3,@dato4,@dato5)
GetDate y GetUTCDate
GetDate devuelve la fecha y hora actuales del sistema en el formato interno
estndar de SQL Server 2005 para los valores datetime.
GetUTCDate devuelve el valor datetime que representa la hora UTC (hora
universal coordinada u hora del meridiano de Greenwich) actual.
Trigger DML.
Los trigger DML se ejecutan cuando un usuario intenta modificar datos mediante
un evento de lenguaje de manipulacin de datos (DML). Los eventos DML son
instrucciones INSERT, UPDATE o DELETE de una tabla o vista.
La sintaxis general de un trigger es la siguiente.
UPDATE CUENTAS
SET SALDO = SALDO + 10
WHERE IDCUENTA = 1
Los trigger estn dentro de la transaccin original (Insert, Delete o Update) por lo
cual si dentro de nuestro trigger hacemos un RollBack Tran, no solo estaremos
echando atrs nuestro trigger sino tambin toda la transaccin; en otras palabras si
en un trigger ponemos un RollBack Tran, la transaccin de Insert, Delete o Update
volver toda hacia atrs.
ROLLBACK
END
Trigger DDL
Los trigger DDL se ejecutan en respuesta a una variedad de eventos de lenguaje
de definicin de datos (DDL). Estos eventos corresponden principalmente a
instrucciones CREATE, ALTER y DROP de Transact-SQL, y a determinados
procedimientos almacenados del sistema que ejecutan operaciones de tipo DDL.
La sintaxis general de un trigger es la siguiente.
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Lectura de la siguiente fila de un cursor
FETCH <nombre_cursor> INTO <lista_variables>
...
END -- Fin del bucle WHILE
-- Cierra el cursor
CLOSE <nombre_cursor>
-- Libera los recursos del cursor
DEALLOCATE <nombre_cursor>
@FxNacimiento datetime
FROM CLIENTES
-- Apertura del cursor
OPEN cClientes
-- Lectura de la primera fila del cursor
FETCH cClientes INTO
WHILE (@@FETCH_STATUS = 0 )
BEGIN
PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2
-- Lectura de la siguiente fila del cursor
FETCH cClientes INTO
END
Descripcin
-1
-2
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 conexin. Puede hacerse
referencia al nombre del cursor en cualquier procedimiento almacenado o proceso
por lotes que se ejecute en la conexin.
FROM CLIENTES
FORWARD_ONLY
Especifica que el cursor slo se puede desplazar de la primera a la ltima fila. FETCH
NEXT es la nica opcin de recuperacin admitida.
FROM CLIENTES
SCROLL
Especifica que estn disponibles todas las opciones de recuperacin (FIRST, LAST,
PRIOR, NEXT, RELATIVE, ABSOLUTE). Si no se especifica SCROLL en una instruccin
DECLARE CURSOR la nica opcin de recuperacin que se admite es NEXT. No es
posible especificar SCROLL si se incluye tambin FAST_FORWARD.
Si se incluye la opcin 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
@Apellido2 varchar(255),
@NifCif varchar(20),
@FxNacimiento datetime
FROM CLIENTES
-- Apertura del cursor
OPEN cClientes
-- Lectura de la primera fila del cursor
FETCH NEXT FROM cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento
WHILE (@@FETCH_STATUS = 0 )
BEGIN
PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2
-- Lectura de la siguiente fila del cursor
FETCH NEXT FROM cClientes
INTO @id,@Nombre,@Apellido1,@Apellido2,@NifCif,@FxNacimiento
END
-- Lectura de la fila anterior
FETCH PRIOR FROM cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento
PRINT @Nombre + ' ' + @Apellido1 + ' ' + @Apellido2
-- Cierre del cursor
CLOSE cClientes
-- Liberar los recursos
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 recuperacin realizadas en el cursor y
adems 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 operacin de recuperacin. La
opcin de recuperacin ABSOLUTE no se puede utilizar en los cursores dinmicos.
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
tambin SCROLL o FOR_UPDATE.
FROM CLIENTES
READ_ONLY
Evita que se efecten actualizaciones a travs de este cursor. No es posible hacer
referencia al cursor en una clusula WHERE CURRENT OF de una instruccin UPDATE
o DELETE. Esta opcin reemplaza la capacidad de actualizar el cursor.
FROM CLIENTES
SCROLL_LOCKS
Especifica que se garantiza que las actualizaciones o eliminaciones posicionadas
realizadas a travs del cursor sern correctas. Microsoft SQL Server bloquea las filas
cuando se leen en el cursor para garantizar que estarn disponibles para futuras
modificaciones. No es posible especificar SCROLL_LOCKS si se especifica tambin
FAST_FORWARD o STATIC.
FROM CLIENTES
OPTIMISTIC
Especifica que las actualizaciones o eliminaciones posicionadas realizadas a travs
del cursor no se realizarn correctamente si la fila se ha actualizado despus de ser
leda 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
comprobacin si la tabla no tiene columnas timestamp, para determinar si la fila se
ha modificado despus de leerla en el cursor. Si la fila se ha modificado, el intento de
actualizacin o eliminacin posicionada genera un error. No es posible especificar
OPTIMISTIC si se especifica tambin FAST_FORWARD.
FROM CLIENTES
TYPE_WARNING
Especifica que se enva un mensaje de advertencia al cliente si el cursor se convierte
implcitamente del tipo solicitado a otro.
FROM CLIENTES
FROM CLIENTES
Para actualizar los datos de un cursor debemos especificar FOR UPDATE despues
de la sentencia SELECT en la declaracin del cursor, y WHERE CURRENT OF
<nombre_cursor> en la sentencia UPDATE tal y como muestra el siguiente ejemplo.
FROM CLIENTES
FOR UPDATE
OPEN cClientes
-- Lectura de la primera fila del cursor
FETCH cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2, @NifCif, @FxNacimiento
WHILE (@@FETCH_STATUS = 0 )
BEGIN
UPDATE Clientes
SET APELLIDO2 = isnull(@Apellido2,'') + ' - Modificado'
WHERE CURRENT OF cClientes
-- Lectura de la siguiente fila del cursor
FETCH cClientes
INTO @id, @Nombre, @Apellido1, @Apellido2,
@NifCif, @FxNacimiento
END
-- Cierre del cursor
CLOSE cClientes
-- Liberar los recursos
DEALLOCATE cClientes
La instruccin EXECUTE
Tambin con SQL dinamico podemos ejecutar sentencias de tipo DDL (Data
Definition Languaje), como CREATE TABLE.