# Curso SQL - DÍA 4
## Variables en SQL
### Declaracion de variables
Las variables en postgresql se declara de la siguiente manera
```sql=
DECLARE vAlt varchar;
```
En donde `vAlt` corresponde al nombre de la variable y `varchar` al tipo de la misma.
Para setear el valor de la variable, se realiza de la siguiente manera:
```sql=
vAlt := 'valor a setear';
```
Tambien se podría declarar la variable con el valor en 1 sola línea, que sería de la siguiente manera:
```sql=
DECLARE vAlt varchar := 'valor a setear';
```
Una variable tambien se puede setear con el resultado de una query:
```sql=
DECLARE vAlt varchar := 'valor a setear';
SELECT name INTO vAlt FROM table WHERE id = 1;
```
### Uso de variables en Queries
#### Clausula WITH
Para usar las variables debemos hacer uso de la clausula `WITH` en postgresql, de la cual se realiza de la siguiente manera:
```sql=
WITH myconstants (var1, var2) as (
values (5, 'foo')
)
SELECT *
FROM somewhere, myconstants
WHERE something = var1
OR something_else = var2;
```
#### Clausula DO
```sql=
DO $$
DECLARE foo TEXT;
BEGIN
foo := 'bar';
SELECT foo;
END $$;
```
```sql=
DO $$
DECLARE
film_count INTEGER;
BEGIN
SELECT COUNT(*) INTO film_count FROM film;
RAISE NOTICE 'The number of films: %', film_count;
END; $$;
```
## Stored Procedure, Functions, Triggers y Views
### Stored Procedure
Un procedimiento almacenado (Stored Procedure) es un bloque de codigo SQL compilado en el cual puede (o no) devolver un resultado (o varios).
La forma de declarar un SP es de la siguiente manera
```sql=
create [or replace] procedure sp_name(parameter_list)
language plpgsql
as $$
declare
-- declaración de variables
begin
-- Código a ejecutar
end; $$
```
En donde:
- **sp_name**: Es el nombre del procedimiento almacenado, se suele comenzar con las siglas **SP_**.
- **parameter_list**: Son los parametros que tiene el procedimiento, puede o no tener los mismos.
- **LANGUAGE**: Es el lenguaje en el cual esta declarado el SP.
- **DECLARE**: Es donde se declaran las variables internas que se van a utilizar en el SP.
- **BEGIN/END**: Es el bloque de codigo que se va a ejecutar.
Veamos un ejemplo mas claro de esto
```sql=
CREATE OR REPLACE PROCEDURE transfer(
sender int,
receiver int,
amount dec
)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE accounts
SET balance = balance - amount
WHERE id = sender;
UPDATE accounts
SET balance = balance + amount
WHERE id = receiver;
COMMIT;
END;$$
```
Y la forma de llamar a un SP es de la siguiente manera:
```sql=
CALL sp_name(parameter_list);
```
En donde:
- **sp_name**: Es el nombre del procedimiento almacenado
- **parameter_list**: Son los parametros que se envían a los mismos.
Y con el ejemplo anterior, a dicho SP se lo podría llamar de la siguiente manera:
```sql=
CALL transfer(1, 2, 1000);
```
[Mas información acerca de Stored Procedure](https://www.postgresql.org/docs/current/sql-createprocedure.html)
### Functions
Una funcion en postgresql, es parecido al SP, con las principales diferencias en que:
- Una funcion esta obligada a devolver solo 1 resultado.
- Una funcion se puede utilizar en una consulta, mientras que en el SP esto no es posible, se debe almacenar el resultado del SP en una variable y luego poder utilizarla.
La forma de declarar una funcion es de la siguiente manera:
```sql=
CREATE [OR REPLACE] FUNCTION function_name (parameter_list)
RETURNS return_type
LANGUAGE plpgsql
AS
$$
DECLARE
-- declaración de variables
BEGIN
--Código a ejecutar
RETURN { variable_name | value }
END;
$$
```
En donde:
- **function_name**: Es el nombre de la funcion.
- **parameter_list**: Son los parametros que tiene el procedimiento, puede o no tener los mismos.
- **RETURNS**: Especifica el tipo de valor que se va a devolver el mismo.
- **LANGUAGE**: Es el lenguaje en el cual esta declarado el SP.
- **DECLARE**: Se declaran las variables internas que se van a utilizar (si es que se utilizan, sino se omite)
- **BEGIN/END**: Es el bloque de codigo que se va a ejecutar.
- **RETURN**: Especifíca el valor a devolver.
Vamos a ver un ejemplo de una función:
```sql=
CREATE FUNCTION get_film_count(len_from int, len_to int)
RETURNS int
LANGUAGE plpgsql
AS
$$
DECLARE
film_count integer;
BEGIN
SELECT COUNT(*)
INTO film_count
FROM film
WHERE length BETWEEN len_from AND len_to;
RETURN film_count;
END;
$$;
```
La forma de llamarlo, es a traves del ``SELECT``.
Para el anterior ejemplo, si lo deberíamos llamar, sería de la siguiente manera:
```sql=
SELECT get_film_count(40,90);
```
[Mas información acerca de Functions](https://www.postgresql.org/docs/current/sql-createfunction.html)
### Triggers
Los triggers, son disparadores que se disparan en acciones definidas en una tabla.
Esto se puede disparar en los siguientes casos:
- Antes de intentar realizar un **INSERT**/**UPDATE**/**DELETE** en una tabla.
- Despues de realizar un **INSERT**/**UPDATE**/**DELETE** en una tabla.
- Reemplazar la accion de un **INSERT**/**UPDATE**/**DELETE**.
En el caso de postgresql, la creacion del trigger, se separa en 2 partes.
La primera, es crear una funcion el cual debe retornar el tipo **TRIGGER**.
La forma de hacerlo es la siguiente:
```sql=
CREATE FUNCTION trigger_function()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
-- Código a ejecutar
END;
$$
```
La segunda parte, consiste en crear el Trigger propiamente dicho, que se realiza de la siguiente manera:
```sql!
CREATE TRIGGER TR_name
{BEFORE | AFTER |INSTEAD OF} { event_name }
ON table_name
[FOR [EACH] { ROW | STATEMENT }]
EXECUTE PROCEDURE trigger_function
```
En donde
- **tr_name**: Hace referencia al nombre del trigger, generalmente con el prefijo **TR_**.
- **BEFORE | AFTER | INSTEAD OF**: En que momento queres que se dispare el trigger, **BEFORE** (Antes), **AFTER** (Despues), **INSTEAD OF** Reemplazando.
- **event_name**: En que evento (**INSERT**, **UPDATE**, **DELETE**, **TRUNCATE**) se dispara el trigger.
- Para el caso de UPDATE, se puede especificar que se dispare cuando se actualiza una columna en particular poniendo **UPDATE OF column_name**.
- **table_name**: Nombre de la tabla en donde se dispara.
- **FOR EACH**: Esto tiene sentido cuando se hace un UPDATE y el mismo afecta a varias columnas.
Esto se puede ver mas claro de la siguiente manera:
```sql=
CREATE OR REPLACE FUNCTION log_last_name_changes()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
IF NEW.last_name <> OLD.last_name THEN
INSERT INTO employee_audits(employee_id,last_name,changed_on)
VALUES(OLD.id,OLD.last_name,now());
END IF;
RETURN NEW;
END;
$$
```
*En el caso de la funcion, se debe devolver **NEW** o **OLD**, para saber si se debe mantener el viejo registro o el nuevo.*
```sql=
CREATE TRIGGER last_name_changes
BEFORE UPDATE
ON employees
FOR EACH ROW
EXECUTE PROCEDURE log_last_name_changes();
```
[Mas información acerca de Triggers](https://www.postgresql.org/docs/current/plpgsql-trigger.html)
### Views
Una vista lo que hace es representar el resulta de una consulta, esto tiene sentido cuando la consulta que se debe realizar se utiliza en varias partes del sistema de diferentes sistemas, y es una consulta compleja, la forma de declarar una vista es de la siguiente manera:
```sql=
CREATE VIEW V_name AS
SELECT column1, column2, columnN
FROM table_name
WHERE column5 = 'ADMIN'
```
En donde:
- **V_name**: Nombre de la vista.
La forma de consumir una vista es como si fuese una tabla, de la misma manera, sería de la siguiente manera:
```sql=
SELECT * FROM V_name;
```
[Mas información acerca de las Views](https://www.postgresql.org/docs/current/sql-createview.html)
## Laboratorios
### Crear una tabla de bitacora sobre la tabla Usuarios
Se debe registrar los cambios de la tabla de Usuarios en una nueva tabla llamada Usuarios_Auditoria.
### Crear dos SP: 1 para la creacion y otro para la actualizacion de un usuario
Se debe crear un SP en el cual le paso los parametros de como crear/modificar un usuario y el mismo debe crear el INSERT del usuario.
### Hacer un Function para que encripte la password del usuario
Se debe crear una funcion que encripte el password del usuario, esta funcion se debe llamar desde el SP de creacion de usuario
### Hacer una Vista de la tabla Usuarios
Se debe crear una vista de la tabla usuarios en el cual se pueda listar los usuarios con su password desencriptado, para esto deben crear otra funcion que desencripte el password.