Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 41

PROGRAMACION TRANSACT-SQL

1. VARIABLES
2. CONTROL DE FLUJO
3. CURSOR
4. FUNCIONES DEFINIDAS POR EL USUARIO
5. PROCEDIMIENTOS ALMACENADOS
6. TRIGGERS

Anexo. Lenguajes DDL y DML

TRANSACT SQL

SQL es un lenguaje de consulta para los sistemas de bases de datos relaciónales,


pero que no posee la funcionalidad algorítmica de un lenguaje de programación.

No permite el uso de:

- Variables
- Estructuras de control de flujo
- Bucles

TRANSACT SQL es un lenguaje de programación que proporciona Microsoft SQL


Server para extender el SQL estándar con la funcionalidad algorítmica de los
lenguajes de programación.
1. VARIABLES

Una variable presenta objetos de un dominio y su valor puede cambiar dentro del
ámbito de un programa.

Se definen dos tipos de variables: locales y globales. Las variables locales están
definidas por el usuario, mientras que las variables globales las suministra el sistema
y están predefinidas.

Variables locales:

o Deben empezar con el sufijo @ y se declaran mediante la palabra clave DECLARE.

o A cada variable local se le debe asignar un tipo de dato:

 De SQL Server distinto de text, image o sysname


 Definido por el usuario o un tipo de

o Se asignan mediante una instrucción SELECT o SET.

Ej1 DECLARE @VarPrecio DECIMAL


SET @VarPrecio = 50

Ej2.
-- declaramos dos variables y le asignamos el máximo y mínimo
-- precio desde la tabla Producto
DECLARE @Maximo DECIMAL, @Minimo DECIMAL

SELECT @Maximo=MAX(Precio), @Minimo=MIN(Precio)


FROM Producto
PRINT 'Precio Mayor: '+STR(@Maximo)
PRINT 'Precio Menor: '+STR(@Minimo)

Salida: Precio Mayor: 45000


Precio Menor: 2350

Variables Globales

Son variables predefinidas suministradas por el sistema. Se distinguen de las


variables locales por tener dos símbolos “@”. Algunas variables globales son:
@@ERROR Contiene 0 si la última transacción se ejecutó de forma
correcta; en caso contrario, contiene el último número de
error generado por el sistema. La variable global @@error
se utiliza generalmente para verificar el estado de error de
un proceso ejecutado.

@@VERSION Devuelve la Versión del SQL Server

@@SERVERNAME Devuelve el Nombre del Servidor

@@LANGUAGE Devuelve el nombre del idioma en uso

@@MAX_CONNECTIONS Devuelve la cantidad máxima de conexiones permitidas

Ej3.
-- Uso de variables globales
PRINT 'Version: ' + @@VERSION
PRINT 'Lenguaje : ' + @@LANGUAGE
PRINT 'Servidor: ' + @@SERVERNAME
PRINT 'Conexiones: ' + STR(@@MAX_CONNECTIONS)

Salida: Version: Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86)
Apr 2 2010 15:53:02
Copyright (c) Microsoft Corporation
Express Edition with Advanced Services on Windows NT 6.1 <X86> (Build
7600: )

Lenguaje: Español
Servidor: JULIOC-PC\SQLEXPRESS
Conexiones: 32767

2. CONTROL DE FLUJO

Se puede utilizar con instrucciones interactivas, en lotes y en procedimientos


almacenados.

Cosntrucciones:

IF-ELSE, CASE, WHILE, BEGIN-END, BREAK, CONTINUE, RETURN [n]

Ej4.
--Mostrar la cantidad de facturas hechas por el empleado
-- de código 6
DECLARE @CodVende INT, @CantFacturas INT
SET @CodVende = 6
SELECT @CantFacturas = COUNT(*)
FROM Factura
WHERE CodVende = @CodVende

--Evalua el valor de CantFacturas


IF @CantFacturas = 0
PRINT 'No ha hecho ninguna factura'
ELSE IF @CantFacturas = 1
PRINT 'Ha hecho 1 factura'
ELSE
PRINT 'Ha hecho varias facturas'
GO

---------
Salida: No ha hecho ninguna factura

Ej5.
--Evaluar la existencia de un registro de Producto;
--si existe actualizamos –precio a $10000 si no existe
--lo insertamos
DECLARE @CodProducto INT, @Descripcion VARCHAR(50), @Precio DECIMAL
SET @CodProducto = 1
SET @Descripcion = 'Aspirina'
SET @Precio = 10000

IF EXISTS(SELECT * FROM Producto WHERE CodProducto = @CodProducto)


BEGIN
UPDATE Producto
SET Precio = @Precio
WHERE CodProducto = @CodProducto
PRINT 'Registro actualizado'
END
ELSE
BEGIN
INSERT INTO ProduCto
VALUES (@CodProducto, 16, @Descripcion, @Precio, 0, 1)
PRINT 'Registro insertado'
END
GO

--------
Salida si existe registro: (1 filas afectadas)
Registro actualizado

Salida si NO existe registro: (1 filas afectadas)


Registro insertado
Estructura CASE
Sintaxis:

CASE <expresión>
WHEN <valor_expresion> THEN <valor_devuelto>
WHEN <valor_expresion1> THEN <valor_devuelto1>
ELSE <valor_devuelto2> -- Valor por defecto
END

Ej6.
--Declarar una variable donde se asigne el número del mes, evalúe el
--valor de la variable y retorne el mes en letras.
DECLARE @M INT, @MES VARCHAR(20)
SET @M=4
SET @MES =
(CASE @M WHEN 1 THEN 'Enero'
WHEN 2 THEN 'Febrero'
WHEN 3 THEN 'Marzo'
WHEN 4 THEN 'Abril'
WHEN 5 THEN 'Mayo'
WHEN 6 THEN 'Junio'
WHEN 7 THEN 'Julio'
WHEN 8 THEN 'Agosto'
WHEN 9 THEN 'Septiembre'
WHEN 10 THEN 'Octubre'
WHEN 11 THEN 'Noviembre'
WHEN 12 THEN 'Diciembre'
ELSE 'no es un mes válido'
END)
PRINT @MES
--------
Salida: Abril

SELECT con una expresión CASE de búsqueda

Ej7.
--Hallar estado del saldo de KardexVtas
DECLARE @Stock INT, @Mes INT
SET @Stock=100
SET @MES=11
SELECT Producto.CodProducto, Producto.Descripcion,
KardexVtas.Mes, KardexVtas.SaldoCant,
'ESTADO'=(CASE WHEN SaldoCant>@Stock THEN 'Cantidad OK'
WHEN SaldoCant=@Stock THEN 'Cantidad en
límite'
WHEN SaldoCant<@Stock THEN 'Hacer pedido'
END)
FROM Producto INNER JOIN KardexVtas
ON Producto.CodProducto = KardexVtas.CodProducto
GO

-------
Salida (Con Resultados a Cuadrícula)

Salida (Con Resultados a Texto)

CodProducto Descripcion Mes SaldoCant ESTADO


----------- -------------------------------------------------- ------ -----------
------------------
1 Aspirina 11 200 Cantidad OK
2 papel1 11 60 Hacer pedido
3 crema 11 70 Hacer pedido
4 Maquina de Afeitar 11 350 Cantidad OK
6 Prod6 11 100 Cantidad en
límite

(5 filas afectadas)

Estructura WHILE

Sintaxis:

WHILE <expresion>
BEGIN
...
END

Ej8.
--Listar los 5 primeros registros de la tabla productos
DECLARE @Contador INT = 1;
WHILE @Contador < 5
BEGIN
SELECT CodProducto, Descripcion, Precio
FROM Producto
WHERE CodProducto=@Contador
SET @Contador += 1;
END;

--------
Salida:

CodProducto Descripcion Precio


----------- --------------------------------------------------
-------------------------------------
1 Aspirina 10000

(1 filas afectadas)

CodProducto Descripcion Precio


----------- --------------------------------------------------
-------------------------------------
2 papel1 3000

(1 filas afectadas)

CodProducto Descripcion Precio


----------- --------------------------------------------------
-------------------------------------
3 crema 4150

(1 filas afectadas)

CodProducto Descripcion Precio


----------- --------------------------------------------------
-------------------------------------
4 Maquina de Afeitar 2560

(1 filas afectadas)

BREAK y CONTINUE

Controlan el funcionamiento de las instrucciones dentro de un bucle WHILE.

o BREAK permite salir del bucle WHILE

o CONTINUE hace que el bucle WHILE se inicie de nuevo.

Sintaxis

WHILE BOOLEAN_EXPRESION
BEGIN
EXPRESION_SQL
[BREAK]
[EXPRESION_SQL]
[CONTINUE]
[EXPRESION_SQL]
END
Ej9.
--Actualizar las unidades de existencia de los productos asignándoles el
--valor de 1000 de aquellos productos cuyo stock sea cero
DECLARE @ID INT, @Descripcion VARCHAR(50)

WHILE EXISTS(
SELECT CodProducto, Mes, SaldoCant FROM KardexVtas
WHERE (SaldoCant=0)
)

BEGIN

SELECT TOP 1 @ID=CodProducto FROM KardexVtas


WHERE (SaldoCant=0)

UPDATE KardexVtas SET SaldoCant=1000


WHERE @ID=CodProducto

SELECT @Descripcion=Descripcion FROM Producto


WHERE CodProducto=@ID
PRINT 'Producto :'+@Descripcion+' actualizado'

END

---------
Salida: 1 filas afectadas)
Producto :crema actualizado

(1 filas afectadas)
Producto :Prod5 actualizado

(1 filas afectadas)
Producto :Prod7 actualizado

Ej10.
--Actualizar las unidades de existencia de los productos asignándoles el
--valor de 1000 de aquellos productos cuyo stock sea cero y codigo < 6
DECLARE @ID INT, @Descripcion VARCHAR(50)

WHILE EXISTS(
SELECT CodProducto, Mes, SaldoCant FROM KardexVtas
WHERE (SaldoCant=0)
)
BEGIN
SELECT TOP 1 @ID=CodProducto FROM KardexVtas
WHERE (SaldoCant=0)
IF @ID > 6 BREAK
UPDATE KardexVtas SET SaldoCant=1000
WHERE @ID=CodProducto

SELECT @Descripcion=Descripcion FROM Producto


WHERE CodProducto=@ID
PRINT 'Producto :'+@Descripcion+' actualizado'
END;

3. CURSOR

Un cursor es una especie de variable apuntador que nos permite recorrer con un
conjunto de resultados obtenidos a través de una sentencia SELECT fila por fila y
hacer referencia a estos uno por uno.

Cuando trabajemos con cursores, debemos seguir los siguientes pasos:

o Declarar el cursor, utilizando DECLARE

o Abrir el cursor, utilizando OPEN

o Leer los datos del cursor, utilizando FETCH ... INTO

o Cerrar el cursor, utilizando CLOSE

o Liberar el cursor, utilizando DEALLOCATE

Declaración de cursor

Sintaxis:

DECLARE <nombre_cursor> [LOCAL | GLOBAL ] --alcance


[ FORWARD_ONLY | SCROLL ] --forma de extracción
[ STATIC | KEYSET | DYNAMIC ] --referencia a filas
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
[ TYPE_WARNING ]
FOR <instruccion_select>
[ FOR { READONLY | UPDATE [ OF lista_columnas ]}]

Donde:

o LOCAL el alcance del cursor es local en el lote, el procedimiento o la función


en curso de ejecución en el que está definido el curso.
o GLOBAL el alcance del cursor es global a la conexión.

o FOWARD_ONLY los datos se extraen del cursor por orden de aparición (del
primero al último).

o STATIC se realiza una copia temporal de los datos en la base de datos


tempdb para que el cursor no se vea afectado por las modificaciones que
puedan realizarse sobre la base de datos.

o KEYSET las filas y su orden en el cursor se fijan en el momento de la apertura


del cursor. Las referencias hacia cada una de estas filas de información se
conservan en una tabla temporal en tempdb.

o DYNAMIC el cursor refleja exactamente los datos presentes en la base de


datos. Esto significa que el número de filas, su orden y su valor pueden variar
de forma dinámica.

o FAST_FORWARD permite definir un cursor hacia adelante y como sólo lectura


(FORWARD_ONLY y READ_ONLY).

o SCROLL_LOCKS permite garantizar el éxito de las instrucciones UPDATE y


DELETE que pueden ser ejecutadas en relación al cursor. Con este tipo de
cursor, se fija un bloqueo en la apertura para evitar que otra transacción trate
de modificar los datos.

o OPTIMISTIC con esta opción, puede que una operación de UPDATE o DLETE
realizada en el cursor no pueda ejecutarse correctamente, porque otra
transacción haya modificado los datos en paralelo.

o TYPE_WARNING se envía un mensaje (warning) a la aplicación cliente, si se


efectúan conversiones implícitas de tipo.

Apertura de un Cursor

Sintaxis

OPEN [ GLOBAL ] <nombre_cursor>

Esta instrucción permite hacer operativo el cursor y crear eventualmente las


tablas temporales asociadas.

Teniendo en cuenta el espacio en disco y la memoria utilizada, y el bloqueo eventual


de los datos en la apertura del cursor, esta operación debe ser ejecutada lo más
cerca
posible del tratamiento de los datos extraídos del cursor.

Lectura de un registro

Sintaxis

FETCH [NEXT | PRIOR | LAST | ABSOLUTE n | RELATIVE n ]


[FROM] [GLOBAL ] <nombre del cursor>
[INTO lista de variables ]
NEXT

Donde:

o FECTCH (=traer el siguiente) Es la única operación de movimiento del cursor

o NEXT lee la fila siguiente (única opción posible para los INSENSITIVE
CURSOR).

o PRIOR lee la fila anterior

o FIRST lee la primera fila

o LAST lee la última fila

o ABSOLUTE n lee la enésima fila del conjunto

o RELATIVE n lee la enésima fila a partir de la fila actual.

Es la instrucción que permite extraer una fila del cursor y asignar valores a variables
con su contenido.

Tras FETCH, la variable @@FETCH_STATUS está a 0 si FETCH no retorna errores.

Cuando trabajamos con cursores, la variable @@FETCH_STATUS nos indica el estado de


la última instrucción FETCH emitida. Los valores posibles son los siguientes:

0 La instrucción FETCH se ejecutó correctamente

-1 La instrucción FETCH no se ejecutó correctamente o


la fila estaba más allá del conjunto de resultados

-2 Falta la fila recuperada


Cerrar el cursor

Sintaxis

CLOSE <nombre_cursor>

Cierra el cursor y libera la memoria. Esta operación debe interponerse lo antes


posible
con el fin de liberar los recursos cuanto antes.

Después de cerrado el cursor, ya no es posible capturarlo o actualizarlo/eliminarlo.

Al cerrar el cursor se elimina su conjunto de claves dejando la definición del cursor


intacta, es decir, un cursor cerrado puede volver a abrirse sin tener que volver a
declararlo.

Liberar los recursos

Sintaxis

DEALLOCATE <nombre_cursor>

Es un comando de limpieza y no forma parte de la especificación ANSI.

Sintaxis básica

-- Declaración del Cursor


DECLARE <NOMBRE_CURSOR> CURSOR
FOR <SENTENCIA_SQL>
-- Apertura del cursor
OPEN <NOMBRE_CURSOR>
-- Lectura de la primera fila
FETCH <NOMBRE_CURSOR> INTO <LISTA_VARIABLES>
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- Lectura de la siguiente fila del cursor
FETCH <NOMBRE_CURSOR> INTO <LISTA_VARIABLES>
...
END – Fin de bucle
-- Cierra el cursor
CLOSE <NOMBRE_CURSOR>
-- Libera recursos del cursor
DEALLOCATE <NOMBRE_CURSOR>

Ej11.
--Con un cursor, mostrar el primer registro de productos
--
DECLARE cursorAProducto CURSOR FOR
SELECT TOP 1 CodProducto, Descripcion, Precio FROM Producto

OPEN cursorAProducto -- Abrir Cursor

FETCH NEXT FROM cursorAProducto --Imprimir primer registro

CLOSE cursorAProducto --Cerrar

DEALLOCATE cursorAProducto --Liberar

---------
Salida:

CodProducto Descripcion Precio


----------- ------------------------------------------------
---------------------------------------
1 Aspirina 10000

(1 filas afectadas)

Ej12.
--Mostrar el primer registro, el registro en la posición 6 y
--el último registro con un cursor

DECLARE cursor_1_Producto CURSOR SCROLL FOR


SELECT CodProducto, Descripcion, Precio FROM Producto

OPEN cursor_1_Producto

PRINT 'Registro: 1'


FETCH FIRST FROM cursor_1_Producto
PRINT 'Registro: 6'
FETCH ABSOLUTE 6 FROM cursor_1_Producto
PRINT 'Registro: ultimo'
FETCH LAST FROM cursor_1_Producto

CLOSE cursor_1_Producto
DEALLOCATE cursor_1_Producto

--------
Salida:

Registro: 1
CodProducto Descripcion Precio
----------- --------------------------------------------------
-------------------------------------
1 Aspirina 10000

(1 filas afectadas)

Registro: 6
CodProducto Descripcion Precio
----------- --------------------------------------------------
-------------------------------------
6 Prod6 7050

(1 filas afectadas)

Registro: ultimo
CodProducto Descripcion Precio
----------- --------------------------------------------------
-------------------------------------
17 Prod17 36000

(1 filas afectadas)

Ej13.
--Con un cursor, listar los Productos registrados
DECLARE @CodProd INT, @NombreProd VARCHAR(50), @Precio
DECIMAL

DECLARE cursor2Prod CURSOR FOR


SELECT CodProducto, Descripcion, Precio
FROM Producto

OPEN cursor2Prod
FETCH cursor2Prod INTO @CodProd, @NombreProd, @Precio

WHILE @@FETCH_STATUS=0
BEGIN
PRINT STR(@CodProd) +','+@NombreProd+','+STR(@Precio)
FETCH cursor2Prod INTO @CodProd, @NombreProd, @Precio
END

CLOSE cursor2Prod
DEALLOCATE cursor2Prod
GO

---------
Salida: 1 Aspirina 10000
2 papel1 3000
3 crema 4150
Ej14.
--Con un cursor, listar los Productos registrados y su saldo
DECLARE @CodProd INT, @NombreProd VARCHAR(50), @Saldo INT
DECLARE cursor3Prod CURSOR FOR

SELECT Producto.CodProducto, Producto.Descripcion,KardexVtas.SaldoCant


FROM KardexVtas INNER JOIN
Producto ON KardexVtas.CodProducto = Producto.CodProducto

OPEN cursor3Prod
FETCH cursor3Prod INTO @CodProd, @NombreProd, @Saldo

WHILE @@FETCH_STATUS=0
BEGIN
PRINT STR(@CodProd)+' '+@NombreProd+' '+STR(@Saldo)
FETCH cursor3Prod INTO @CodProd, @NombreProd, @Saldo
END

CLOSE cursor3Prod
DEALLOCATE cursor3Prod
GO

--------
Salida: 1 Aspirina 200
2 papel1 60
3 crema 1000
4 Maquina de Afeitar 350
5 Prod5 0
6 Prod6 100
7 Prod7 0

Para actualizar los datos de un cursor,

SELECT
FOR UPDATE después de la sentencia en la declaración del cursor, y
WHERE CURRENT OF <nombre_cursor> en la sentencia UPDATE.

DECLARE <nombre_cursor> …
FOR <instruccion_select>

FOR UPDATE [ OF lista_columnas ]

Ej15. actualizar el precio de los productos:


si su stock >= 100 descuentar el precio al 50%,
sino descontar el precio al 20%.

Análisis:
Declarar variables DECLARE @varStock, @varPrecio, @Var2, ..

Declarar cursor DECLARE cursorcito FOR


Seleccionar datos SELECT …
Declarar opción de actualización FOR UPDATE

Abrir cursor OPEN cursorcito


Leer primer registro en variables FETCH cursorcito INTO @varStock, @varPrecio

Bucle
WHILE(Condición) WHILE (@@FETCH_STATUS = 0 )
Inicio Bloque BEGIN
Evaluar stock IF @varStock >= 100
SET @varPrecio = @varPrecio*0.50
ELSE
SET @varPrecio = @varPrecio*0.80

Actualizar registro UPDATE


Leer próximo registro FETCH cursorcito INTO @varStock, @varPrecio

Fin Bloque END

-- actualizar el precio de los productos:


-- si su stock >= 100 descuentar el precio al 50%,
-- sino descontar el precio al 20%.

DECLARE @varCodProducto INT,


@varDescripcion VARCHAR(50), @varPrecio DECIMAL,
@precioAux INT, @varStock INT, @varContador INT
SET @varContador=0

DECLARE cursorcito CURSOR FOR


--
SELECT Producto.CodProducto,Producto.Descripcion,Producto.Precio,
KardexVtas.SaldoCant
FROM KardexVtas INNER JOIN
Producto ON KardexVtas.CodProducto=Producto.CodProducto
--
FOR UPDATE

OPEN cursorcito
FETCH cursorcito INTO @varCodProducto, @varDescripcion,
@varPrecio, @varStock
SET @precioAux=@varPrecio
WHILE (@@FETCH_STATUS = 0 )
BEGIN
IF @varStock>=100 SET @varPrecio = @varPrecio*0.5
ELSE SET @varPrecio = @varPrecio*0.8

SET @varContador = @varContador+1

UPDATE Producto SET Precio = @varPrecio


WHERE CURRENT OF cursorcito

PRINT 'Precio '+ @varDescripcion+ ' De '+ STR(@precioAux)+


' a '+ STR(@varPrecio)
FETCH cursorcito INTO @varCodProducto, @varDescripcion,
@varPrecio, @varStock
SET @precioAux=@varPrecio
END

PRINT 'Se modificaron '+ STR(@varContador) + ' registros'


CLOSE cursorcito
DEALLOCATE cursorcito

-------
Salida:

(1 filas afectadas)
Precio PROD1 De 1500 a 1200

(1 filas afectadas)
Precio PROD2 De 3000 a 2400

(1 filas afectadas)
Precio PROD3 De 4150 a 3320

(1 filas afectadas)
Precio PROD4 De 2560 a 1280

(1 filas afectadas)
Precio PROD5 De 1200 a 600

(1 filas afectadas)
Precio PROD6 De 3500 a 1750

(1 filas afectadas)
Precio PROD7 De 2350 a 1880

Se modificaron 7 registros

4. FUNCIONES DEFINIDAS POR EL USUARIO

Al igual que las funciones en los lenguajes de programación, en SQL Server las
funciones definidas por el usuario son rutinas:
o Aceptan parámetros
o Realizan una acción, como un cálculo complejo,
o Devuelven el resultado de esa acción como un valor. 

El valor devuelto puede ser un valor escalar único o un conjunto de resultados.

Los beneficios del uso de funciones definidas por el usuario en SQL Server son:

o Permiten la programación modular.


o Permiten una ejecución más rápida.
o Puede reducir el tamaño de datos en red.

Funciones escalares

Devuelve un solo valor de dato del tipo definido en la cláusula RETURNS. 

Para una función escalar de varias instrucciones:

o Definir el cuerpo de la función en un bloque BEGIN ... END


o Ingresar en el cuerpo de la función instrucciones Transact-SQL
o Retornar único valor. 
o El tipo de retorno puede no puede ser del tipo text, ntext, image, cursor ni
timestamp.

Ej15.
-- Funcion que retorna el valor del saldo de un producto
-- en el kardex
--
CREATE FUNCTION valorPK(@CodProd int)
RETURNS MONEY
AS
BEGIN
DECLARE @valorProd int

SELECT @valorProd = SaldoVr


FROM KardexVtas
WHERE CodProducto=@CodProd

IF (@valorProd IS NULL) SET @valorProd = 0


RETURN @valorProd
END

-----------------
Para Ejecución:
PRINT dbo.valorPK(1)
GO
Salida:
135000.00

Ej16.
-- Funcion que retorna la cantidad de saldo de un producto
-- en el kardex
--
CREATE FUNCTION cantPK(@CodProd int)
RETURNS INT
AS
BEGIN
DECLARE @varCantProd int

SELECT @varCantProd = SaldoCant


FROM KardexVtas
WHERE CodProducto=@CodProd

IF (@varCantProd IS NULL) SET @varCantProd = 0


RETURN @varCantProd
END

--------
Para ejecución:

PRINT 'Cantidad producto 1: '+STR(dbo.cantPK(1))

Salida: Cantidad producto 1: 90

Para ejecución con asignación:

DECLARE @Cant INT


set @Cant=dbo.cantPK(1)
PRINT 'Cantidad de producto 1'+STR(@Cant)
GO

Salida: Cantidad producto 1: 90

Ej17.
-- Funcion que retorna el precio de un producto
-- en el catalogo
--
CREATE FUNCTION [dbo].[precioProd](@CodProd int)
RETURNS MONEY
AS
BEGIN
DECLARE @valorProd int

SELECT @valorProd = Precio


FROM Producto
WHERE CodProducto=@CodProd

IF @@ROWCOUNT = 0 SET @valorProd = -1


ELSE IF (@valorProd IS NULL) SET @valorProd = 0
RETURN @valorProd
END

-----------------
Para ejecución:
PRINT dbo.precioProd(1)
go

Salida (Si existe producto en el catalogo):

1500.00

Salida (Si existe producto en el catalogo):

-1.00
Ej18
-- Reportar el precio promedio de los productos registrados
--
CREATE FUNCTION PRECIOPROMEDIO]()
RETURNS MONEY
AS
BEGIN
DECLARE @PROM MONEY
SELECT @PROM=AVG(Precio)
FROM Producto

RETURN @PROM
END

Funciones con valores de tabla

Devuelve la salida de una simple declaración SELECT. La salida se puede utilizar


adentro de JOINS o querys como si fuera una tabla de estándar.

Sintaxis:

CREATE FUNCTION [propietario.] nombre_funcion


([{ @parameter tipo de dato [ = default]} [,..n]])
RETURNS TABLE
[AS]
RETURN [(] Sentencia SQL [)]

Ej19.
--Función que liste el kardex incluyendo los nombres de los
--productos y el precio
CREATE FUNCTION muestraKardex()
RETURNS TABLE
AS

RETURN
(SELECT Producto.CodProducto, Producto.Descripcion,
Producto.Precio, KardexVtas.SaldoCant
FROM KardexVtas INNER JOIN
Producto ON KardexVtas.CodProducto =
Producto.CodProducto
)
GO

----------
Para ejecución
SELECT * FROM muestraKardex()

Salida:

CodProducto Descripcion Precio SaldoCant


----------- ---------------------------- --------------------- -----------------------------------
1 PROD1 1500 80
2 PROD2 3000 60
3 PROD3 4150 70
4 PROD4 2560 350
5 PROD5 1200 120
6 PROD6 3500 100
7 PROD7 2350 80

(7 filas afectadas)

----------------
Para ejecución:
DECLARE @N INT
SELECT @N=COUNT(*) FROM muestraKardex()
PRINT 'FILAS RETORNADAS '+STR(@N)
GO

Salida:
FILAS RETORNADAS 7

5. PROCEDIMIENTOS ALMACENADOS

o Los procedimientos almacenados son grupos formados por instrucciones SQL y


el lenguaje de control de flujo.

o Los procedimientos mejoran la potencia, velocidad, eficacia y flexibilidad de


SQL.

o Los procedimientos almacenados se diferencian de las instrucciones SQL


ordinarias y de lotes de instrucciones SQL en que están pre-compilados.

o Los procedimientos almacenados se crean con CREATE PROCEDURE


Para ejecutar EXECUTE nombreProcedimiento ó nombreProcedimiento

Los procedimientos almacenados pueden:

o Incluir parámetros

o Llamar a otros procedimientos


o Devolver un valor de estado a un procedimiento de llamada o lote para indicar
el éxito o el fracaso del mismo y la razón de dicho fallo.

o Devolver valores de parámetros a un procedimiento de llamada o lote


Sintaxis para crear un procedimiento almacenado:

CREATE PROCEDURE <Procedure_Name>


-- Añadir parámetros al procedimiento almacenado
<@Param1> <Datatype> = <Default_Value>,
<@Param2> <Datatype> = <Default_Value>
AS
BEGIN
-- Insertar la sentencia para el procedimiento
Sentencia SQL
END

Sintaxis para modificar un procedimiento almacenado:

ALTER PROCEDURE NOMBRE_PROCEDIMIENTO


<@Param1> <Datatype> = <Default_Value>,
<@Param2> <Datatype> = <Default_Value>
AS
CONSULTA_SQL

Ej20.
--procedimiento almacenado que liste todos los clientes
CREATE PROCEDURE listaProds
AS
BEGIN
SELECT CodProducto, Descripcion, Precio, PorcIva
FROM Producto
END
GO

----------
Ejecución

EXEC listaProds ó listaProds


GO GO
Procedimiento almacenado con parámetros de entrada

Ej.21
--Buscar un producto.
CREATE PROCEDURE buscaProd
@VarCodProd INT
AS
BEGIN
SELECT CodProducto, Descripcion, Precio, PorcIva
FROM Producto
WHERE CodProducto=@VarCodProd
END
GO

-----------
Ejecución: buscaProd 1
GO

Modificar Procedimiento almacenado

Ej22. --Buscar un rango de productos


USE [VENTAS]
GO
/****** Object: StoredProcedure [dbo].[buscaProd] Script Date:
11/09/2012 15:46:02 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--Buscar un producto.
ALTER PROCEDURE [dbo].[buscaProd]
@VarCodProd1 INT,
@VarCodProd2 INT
AS
BEGIN
SELECT CodProducto, Descripcion, Precio, PorcIva
FROM Producto
WHERE CodProducto>=@VarCodProd1 AND
CodProducto<=@VarCodProd2
END

-----------
----------
Ejecución: buscaProd 1,3
GO
Salida:

CodProducto Descripcion Precio PorcIva


----------- -------------------- --------------------------------------- ----------------------
1 PROD1 1500 16
2 PROD2 3000 10
3 PROD3 4500 12

(3 filas afectadas)

Ej23.
–ingresar un producto
CREATE PROCEDURE addRegProd
@CodProd int,
@PorcIva float,
@Descrip varchar(50),
@Precio decimal

AS
INSERT INTO Producto
VALUES(@CodProd,@PorcIva, @Descrip,@Precio,0,1)

IF @@ERROR=0
PRINT 'Cliente Registrado'
ELSE
PRINT 'Cliente Ya Existe'

---------
Ejecución: addRegProd 18,16,'ProdX', 13250
GO

Salida
Si no está: (1 filas afectadas)
Cliente Registrado

TRANSACCIONES EN TRANSACT-SQL

Una transacción es un conjunto de operaciones TRANSACT SQL que se ejecutan


como un único bloque, es decir, si falla una operación TRANSACT SQL fallan todas.

Para agrupar varias sentencias TRANSACT SQL en una única transacción,


disponemos de los siguientes métodos:

Transacciones explícitas: Cada transacción:

o Se inicia explícitamente con la instrucción BEGIN TRANSACTION y


o Se termina explícitamente con una instrucción COMMIT o ROLLBACK.

Transacciones implícitas:

o Se inicia automáticamente con instrucción que modifique datos

o Se completa explícitamente con una instrucción COMMIT o ROLLBACK.

Sintaxis para el control de las transacciones:

BEGIN TRAN NombreTransaccion -- inicio de transacción con nombre



instrucciones a ejecutar en la transacción

COMMIT TRAN NombreTransaccion --Confirmación de la transacción
ROLLBACK TRAN NombreTransaccion --Reversión de la transacción

Ej24. –- Ingresar un producto como una transacción

CREATE PROCEDURE addRegProdT


@CodProducto INT, @PorcIva FLOAT, @Descripcion VARCHAR(50),
@Precio DECIMAL, @PorcDescto FLOAT, @CodTipo SMALLINT

AS
BEGIN TRAN TProd
INSERT INTO Producto
VALUES(@CodProducto,@PorcIva,@Descripcion,@Precio,
@PorcDescto,@CodTipo)
GO
IF @@ERROR=0
BEGIN
COMMIT TRAN TProd
PRINT 'Cliente Registrado'
END
ELSE
BEGIN
PRINT 'Error-Codigo registro ya existe'
ROLLBACK TRAN TProd
END

-----------
Para ejecución:
addRegProdT 50,15,'PROD50',15250,15,1
GO
Salida (Si ya existe el registro con el valor de clave 50):

Mens 2627, Nivel 14, Estado 1, Procedimiento addRegProdT, Línea 11


Infracción de la restricción PRIMARY KEY 'PK_Producto_1'. No se puede insertar una clave duplicada
en el objeto 'dbo.Producto'.
Se terminó la instrucción.
Error-Código registro ya existe

Salida (Si NO existe el registro con el valor de clave 50):


(1 filas afectadas)
Cliente Registrado

Uso de instrucciones Try-Catch

Sintaxis Try-Catch

BEGIN TRY
/*Bloque de instrucciones a validar*/
END TRY

BEGIN CATCH
/*Bloque de instrucciones que se ejecutan si ocurre un ERROR*/
END CATCH

Para un mejor control de los errores se pueden ejecutar los procesos dentro un
bloque TRY-CATCH donde:

o En el caso de éxito en las operaciones se ejecutará COMMIT TRAN

o En caso de error (CATCH), se ejecutará ROLLBACK TRAN

Ej25.
-- Ingresar un producto como una transacción
-- con instrucciones try-catch
CREATE PROCEDURE addRegProdT_ConTC
@CodProducto INT, @PorcIva FLOAT, @Descripcion VARCHAR(50),
@Precio DECIMAL, @PorcDescto FLOAT, @CodTipo SMALLINT

AS
BEGIN TRAN TProd

BEGIN TRY
INSERT INTO Producto
VALUES(@CodProducto,@PorcIva,@Descripcion,@Precio,
@PorcDescto,@CodTipo)
COMMIT TRAN TProd
PRINT 'Cliente Registrado'
END TRY

BEGIN CATCH
PRINT 'Error-Codigo registro ya existe'
ROLLBACK TRAN TProd
END CATCH
GO

---------
Salida (Si ya existe el registro con el valor de clave 50):

(0 filas afectadas)
Error-Codigo registro ya existe

Salida (Si NO existe el registro con el valor de clave 50):


(1 filas afectadas)
Cliente Registrado

Ej26. --Registro de venta de producto en ElemFra


--con transaccion de actualización sobre kardex
--
CREATE PROC addElemFra
@NroFactura INT,@CodProd INT,@CodLaborat INT,@Cantidad INT
AS

DECLARE @Precio INT, @SaldoCant INT,@SaldoVr INT, @Valor INT

BEGIN TRAN TElemFra

BEGIN TRY

INSERT INTO ELEMFRA


VALUES(@NroFactura,@CodProd,@CodLaborat,@Cantidad)

SELECT @SaldoCant=SaldoCant, @SaldoVr=SaldoVr


FROM KardexVtas WHERE CodProducto=@CodProd

IF (@SaldoCant-@Cantidad)<0
PRINT 'Transaccion de venta genera Saldo Kardex < 0'

SELECT @Precio=Precio FROM Producto


WHERE CodProducto=@CodProd
SET @Valor=@Cantidad*@Precio

UPDATE KardexVtas
SET SaldoCant-=@Cantidad, SaldoVr-=@Valor,
VentasCant+=@Cantidad, VentasVr+=@Precio
WHERE CodProducto=@CodProd

COMMIT TRAN TElemFra


PRINT 'Venta registrada OK'

END TRY

BEGIN CATCH
ROLLBACK TRAN TElemFra
PRINT 'Venta NO registrada'
END CATCH

-----------
Ejecución: addElemFra 1,3,1,10
GO

Salida: Si el saldo del producto en el kárdex se vuelve negativo con la


transacción:
(1 filas afectadas)
Transaccion de venta genera Saldo Kardex < 0

(0 filas afectadas)
Venta NO registrada

Si el saldo del producto en el kárdex sigue siendo >= 0 con la


transacción:
(1 filas afectadas)

(1 filas afectadas)
Venta registrada OK

Nota. Para que el DBMS reconozca este error la columna SaldoCant del Kárdex debe
ser restringida a contener valores >= 0.

6. TRIGGERS

Un disparador es un tipo especial de procedimiento almacenado que se ejecuta


cuando se insertan, eliminan o actualizan datos de una tabla especificada.
Los disparadores pueden ayuda a mantener la integridad de referencia de los datos
conservando la consistencia entre los datos relacionados lógicamente de distintas
tablas.

La principal ventaja de los disparadores es que son automáticos: funcionan cualquiera


sea el origen de la modificación de los datos.

Cada disparador es específico de una o más operaciones de modificación de datos, UPDATE,


INSERT o DELETE. El disparador se ejecuta una vez por cada instrucción.

Sintaxis para crear un trigger

CREATE TRIGGER [ esquema. ]nombre_trigger


ON { Tabla | Vista }
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS
sentencia sql [ ; ]

Sintaxis para modificar un trigger

ALTER TRIGGER [ esquema. ]nombre_trigger


ON { Tabla | Vista }
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS
sentencia sql [ ; ]

Para eliminar un trigger: DROP TRIGGER TX_PRODUCTOS

Ej27.
--imprimir un mensaje cada vez que alguien trata de
-- insertar, eliminar o actualizar datos de la tabla Producto
CREATE TRIGGER tAct1Producto
ON Producto
FOR INSERT, UPDATE, DELETE
AS
PRINT 'Actualizacion de los registros de Productos'

Modificar un trigger
Ej28.
--imprimir un mensaje cada vez que alguien trata de
-- insertar, eliminar o actualizar datos de la tabla Producto
ALTER TRIGGER tAct1Producto
ON Producto
FOR INSERT, UPDATE, DELETE
AS
PRINT 'Tabla productos actualizada'

-----------------
Para ejecución:
UPDATE Producto
SET Precio = 12500
WHERE CodProducto=1
GO

Salida con trigger tAct1Producto (en dependencias de tabla)


Tabla productos actualizada

(1 filas afectadas)

Disparador de Inserción.

Cuando se inserta una nueva fila en una tabla:


SQL Server inserta los nuevos valores en la tabla del sistema INSERTED:

Está tabla toma la misma estructura de la cual se originó el TRIGGER, de tal manera
que se pueda verificar los datos y ante un error podría revertirse los cambios.

Ej29.
--insertar los datos de un Producto siempre y cuando la
--descripción o nombre del producto sea único.
CREATE TRIGGER tIngresarProd
ON Producto
FOR INSERT
AS

DECLARE @NomProdsIguales INT

SELECT @NomProdsIguales=COUNT (*)


FROM INSERTED, Producto
WHERE INSERTED.Descripcion = Producto.Descripcion

IF @NomProdsIguales > 1
BEGIN
ROLLBACK TRANSACTION
PRINT 'Descripcion de producto ya registrada'
END
ELSE PRINT 'Producto ingresado OK'
GO

-----------------
Para ejecución:
INSERT INTO Producto
VALUES(55,16,'Prod55',8520,10,1)
GO

Salida (si NO existe Prod55 en la tabla):

Tabla productos actualizada por trigger tAct1Producto


Producto ingresado OK por trigger t1IngresaProd

(1 filas afectadas)

-----------------
Para ejecución:
INSERT INTO Producto
VALUES(55,16,'Prod55',8520,10,1)
GO

Salida (SI existe Prod55 en la tabla):

Tabla productos actualizada por trigger tAct1Producto


Error-Descripcion de producto ya existe por trigger t1IngresaProd
Mens. 3609, Nivel 16, Estado 1, Línea 1
La transacción terminó en el desencadenador. Se anuló el lote.

Ej30. --Cargar fecha actual en campo de fecha


-- al ingresar factura
--
ALTER TRIGGER tFechaFra
ON Factura
FOR INSERT
AS

UPDATE Factura
SET FechaFra=GETDATE()
WHERE Factura.NroFactura=(
SELECT INSERTED.NroFactura
FROM INSERTED
WHERE Factura.NroFactura=INSERTED.NroFactura
)
Disparador de Eliminación.

Cuando se elimina una fila de una tabla:


SQL Server inserta los valores que fueron eliminados en la tabla del sistema DELETED.

Está tabla toma la misma estructura del cual se origino el TRIGGER, de tal manera que se
pueda verificar los datos y ante un error podría revertirse los cambios.

En este caso, la reversión de los cambios significará restaurar los datos eliminados.

Ej31.
--eliminar Cliente del cuales no han registrado algún
--factura. De eliminarse algún Cliente que no cumpla con dicha
--condición la operación
--no deberá ejecutarse.
--
CREATE TRIGGER t1BorraCliente
ON Cliente
FOR DELETE
AS
IF EXISTS (SELECT * FROM Factura
WHERE Factura.CodCliente =
(SELECT CodCliente FROM DELETED) )
BEGIN
ROLLBACK TRANSACTION
PRINT 'ERROR-Cliente tiene registradas facturas'
END

-----------------
Para ejecución:

DELETE FROM Cliente


WHERE CodCliente=2
GO

Salida (SI existe CodCliente = 2 en tabla Factura):

ERROR-Cliente tiene registradas facturas


Mens. 3609, Nivel 16, Estado 1, Línea 1
La transacción terminó en el desencadenador. Se anuló el lote.

Salida (NO existe CodCliente = 2 en tabla Factura):

(1 filas afectadas)

Nota. Las tablas involucradas en este proceso NO deben tener relación alguna.
En ekl anterior ejemplo, la tabla Cliente es libre.

Disparador de Actualización

Cuando se actualiza una fila de una tabla:

SQL Server inserta los valores antiguos en la tabla DELETED


e inserta los valores nuevos en la tabla INSERTED.

Usando estas dos tablas se podrá verificar los datos y ante un error podrían revertirse los
cambios.

Ej32.
--validar que el precio unitario de un producto
--no pueda ser actualizado como <=0
--
CREATE TRIGGER tValidaProdK
ON Producto
FOR UPDATE
AS
IF (SELECT Precio FROM INSERTED)<=0
BEGIN
PRINT 'ERROR- el precio no puede ser actualizado a <=0'
ROLLBACK TRANSACTION
END
ELSE PRINT 'Precio actualizado-OK'

-----------------
Para ejecución:
UPDATE Producto
SET Precio = 11111
WHERE CodProducto=1
GO

Salida:
Precio actualizado-OK
Tabla productos actualizada

(1 filas afectadas)

-----------------
Para ejecución:

UPDATE Producto
SET Precio = -3250
WHERE CodProducto=1
GO
Salida:
ERROR- el precio no puede ser actualizado a <=0
Mens. 3609, Nivel 16, Estado 1, Línea 1
La transacción terminó en el desencadenador. Se anuló el lote.

Uso de INSTEAD OF (en lugar de)

Se puede definir un desencadenador INSTEAD OF para realizar comprobación de


errores o valores en una o más columnas y, a continuación, realizar acciones
adicionales antes de insertar el registro.

INSTEAD OF INSERT

Se pueden definir desencadenadores INSTEAD OF INSERT en una vista o tabla para


reemplazar la acción estándar de la instrucción INSERT.

Normalmente, el desencadenador INSTEAD OF INSERT se define en una vista para


insertar datos en una o más tablas base.

Ej. Vista que lista Productos:

CREATE VIEW vistaTablaProd AS


SELECT CodProducto, PorcIva, Descripcion, Precio, PorcDescto, CodTipo
FROM dbo.Producto

Ej33. -- Trigger INSTEAD OF INSERT para vista Producto


--
CREATE TRIGGER tInsertVistaProd ON vistaTablaProd
INSTEAD OF INSERT
AS
BEGIN

INSERT INTO Producto (SELECT * FROM INSERTED)

PRINT 'datos insertados en tabla desde vista'

END
ANEXO

Lenguaje DML

Operadores aritméticos: + - * / %

%: Devuelve el resto entero de una división. Por ejemplo, 12 % 5 = 2


porque el resto de 12 dividido entre 5 es 2.

Operador de asignación: =

DECLARE @NUM INT


SET @NUM=15
PRINT 'EL NUMERO INGRESADO ES:' + STR(@NUM)

Operadores de comparación: =, >, <, >=, <=, <>

Algunos Operadores lógicos: ALL, AND, ANY, BETWEEN, EXISTS, IN, NOT, OR, SOME

Ej. 1
--mostrar los productos com precio entre 2000 y 8000
--
SELECT Elemfra.CodProducto, Producto.Descripcion, Producto.Precio,
Producto.PorcIva, Producto.PorcDescto
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto
WHERE (Producto.Precio > 2000 AND Producto.Precio < 8000)

Ej2.
--mostrar los productos com precio entre 2000 y 8000
--
SELECT Elemfra.CodProducto, Producto.Descripcion, Producto.Precio,
Producto.PorcIva, Producto.PorcDescto
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto
WHERE Producto.Precio BETWEEN 2000 AND 8000

Ejemplo de una función de fecha


Ej3. -- funciones de fecha
PRINT GETDATE()
GO

PRINT DATEPART(year,GETDATE())
GO
PRINT DATEPART(MONTH,GETDATE())
GO
PRINT DATEPART(DAY,GETDATE())
GO
PRINT DATEPART(HOUR,GETDATE())
GO
PRINT DATEPART(MINUTE,GETDATE())
GO
PRINT DATEPART(SECOND,GETDATE())
GO
PRINT DATEPART(WEEK,GETDATE())
GO

Comandos DML

Insertar registros: INSERT

Ej. 4
--Insertar un único registro especificando todos los campos a ingresar
--
INSERT INTO Cliente (CodCliente, NOmbre, Dir, Telefono)
VALUES (100, 'juanita banana','calle 10','123456789')
GO

Ej5.
--Insertar un único registro especificando únicamente los
--valores de los campos
--
INSERT INTO Cliente
VALUES (101, 'pepita perez','calle 10','123456789')
GO

Ej6.

--Insertar varias filas de datos


--
INSERT INTO Cliente
VALUES (102, 'maria engracia','calle 10','123456789'),
(103, 'pepita mendieta','calle 10','123456789'),
(104, 'luisa lane','calle 10','123456789')
GO

Actualización de datos: UPDATE

Sintaxis:

UPDATE Nombre_tabla
SET nombre_columna1 = expr1, nombre_columna2 = expr2,…...
[WHERE {condición}]

Ej8.

--Actualizar varias columnas


--
UPDATE Producto
SET Precio *= 1.25, PorcDescto *= 1.5, PorcIva *= 1.3

GO

Eliminación de datos: DELETE

Sintaxis

DELETE FROM Nombre_Tabla


[WHERE { condición }]

Selección de datos : SELECT

Sintaxis:
SELECT [ALL|DISTINCT] [TOP (expresión) [PERCENT] [WITH TIES] ]
< lista de selección >
[INTO nombre de la nueva tabla]
FROM <nombre de tabla>
WHERE <condición>
GROUP BY <nombre de campos>
HAVING <condición> [AND | OR <condición>]
ORDER BY

Ej9.
--mostrar los productos com precio entre 2000 y 8000
--
SELECT Elemfra.CodProducto, Producto.Descripcion, Producto.Precio,
Producto.PorcIva, Producto.PorcDescto
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto
WHERE (Producto.Precio > 2000 AND Producto.Precio < 8000)

Ej10.
--Mostrar los productos vendidos al cliente 1 que sean
--mayores a 3000
SELECT Producto.Descripcion, Factura.CodCliente, Producto.Precio
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto
INNER JOIN
Factura ON Elemfra.NroFactura = Factura.NroFactura
WHERE (Factura.CodCliente = 1) AND (Producto.Precio > 3000)

Ej11.
--Mostrar la suma de las ventas
--
SELECT SUM(Elemfra.Cantidad * Producto.Precio) AS [Valor venta]
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto

-------
Salida:
Valor venta
---------------------------------------
511740

(1 filas afectadas)
Ej12.
--Mostrar la suma de las ventas al cliente 1
--
SELECT SUM(Elemfra.Cantidad * Producto.Precio) AS [Valor venticas],
Factura.CodCliente AS Clientecito
FROM Elemfra INNER JOIN
Producto ON Elemfra.CodProducto = Producto.CodProducto
INNER JOIN
Factura ON Elemfra.NroFactura = Factura.NroFactura
GROUP BY Factura.CodCliente
HAVING (Factura.CodCliente = 1)

------
Salida:

Valor venticas Clientecito


--------------------------------------- -----------
511740 1

(1 filas afectadas)

También podría gustarte