15/10/2014 Expresiones Join SQL2 En SQL2 hay varias clases de operadores Join disponibles. Las expresiones Join, al producir relaciones, pueden ser usadas en la cláusula FROM de una expresión Seleccione-De-Cuando. La forma más simple de expresión Join es el CROSS JOIN, término sinónimo del producto cartesiano. Por ejemplo, si queremos realizar el producto de dos relaciones: Películas (titulo, año, longitud, tipo, estudio) Estrellas (tituloPelicula, añoPelicula, nombreActor) Podemos hacerlo asi: Películas CROSS JOIN Estrellas; Suponga que deseo unir las relaciones Películas y Estrellas con la condición de unir solo aquellas tuplas que se refieran a la misma película. Es decir, que tituloPelicula y año deben ser el mismo. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 1 Expresiones Join SQL2 El resultado puede ser: Películas JOIN Estrellas ON titulo = tituloPelicula AND año = añoPelicula; El resultado es una relacion de ocho columnas con los mismos atributos del CROOSJOIN donde las tuplas resultantes provienen de aquellas tuplas de Películas y Estrellas que al combinarlas coincidan en el titulo y el año de la película. Cuando una expresión Join aparece en una cláusula FROM, la relación denotada por la expresión Join es tratada como una tabla base o una vista en la cláusula FROM. Ejemplo: Si consideramos que el ejemplo anterior tiene dos componentes redundantes, toda la expresión del ejemplo se pueden colocar en la cláusula FROM y usar una cláusula SELECT para remover los atributos no deseados: 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 2 1 15/10/2014 Expresiones Join SQL2 SELECT titulo, año, longitud, tipo, estudio, nombreActor FROM Películas JOIN Estrellas ON Titulo = tituloPelicula AND año = añoPelícula ; JOIN NATURAL EN SQL2 Como se recuerda el Join natural difiere del Join theta en: 1. La condición join es que todos los atributos que se emparejan, de las dos relaciones tienen un nombre comun que se iguala, y no hay otras condiciones. 2. Uno solo de los atributos que se igualan son proyectados. SQL2 funciona exactamente así, la palabra clave NATURAL JOIN debe aparecer entre las relaciones para expresar el operador ⊲⊳ . Bases de Datos I - Mauricio E. Fernández N 15/10/2014 3 Expresiones Join SQL2 Ejemplo: se quiere calcular el join natural de las relaciones: EstrellasPelicula (nombre, dirección, sexo, fechaNacmto) EjecutivosCine (nombre, dirección, codProductor, ingresoNeto) La consulta será: EstrellasPelicula NATURAL JOIN EjecutivosCine ; OUTERJOIN EN SQL2 Al calcular el join R ⊲⊳ S, si una tupla t de R no se iguala con una tupla de S, todos los datos de t desaparecen del resultado. El outerjoin difiere del join ordinario ( o “inner” ) al adicionar al resultado cualquier tupla de cualquier relación que no iguale con al menos una tupla de la otra relación. Las tuplas colgantes se rellenan con NULL en los atributos que no se igualan. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 4 2 15/10/2014 Expresiones Join SQL2 Queremos obtener aquellos individuos que son estrellas pero no ejecutivos o los ejecutivos que no son estrellas. Entonces se debe utilizar “natural full outer join”: EstrellasPelicula NATURAL FULL OUTER JOIN EjecutivosCine; El resultado es una relación con seis atributos, con dos tipos de tuplas: a) los individuos que son estrellas pero no ejecutivos (los atributos de EjecutivosCine con NULL); y b) las que representan ejecutivos pero no estrellas (los atributos de EstrellasPelicula con NULL). Existen muchas variaciones de la reunión externa (outerjoin) disponibles en SQL2. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 5 Expresiones Join SQL2 a) El left outerjoin, donde solo las tuplas colgadas de la relación izquierda son rellenadas con nulos e incluidas en el resultado: EstrellasPeliculas NATURAL LEFT OUTER JOIN EjecutivosCine; b) El right outerjoin, donde se rellena e incluye solo las tuplas colgadas de la segunda relación (derecha): EstrellasPeliculas NATURAL RIGHT OUTER JOIN EjecutivosCine; Otra variación en los outerjoin es cuando se especifica la condición que las tuplas que igualen deben cumplir. En vez de la palabra NATURAL, al join debe seguirle el ON y una condición que al igualar las tuplas, estas deban satisfacer: c) El FULLOUTERJOIN, donde después de igualar tuplas, se rellenan las tuplas colgantes de cualquiera de las relaciones con valor NULL, incluyendo en el resultado las tuplas rellenadas. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 6 3 15/10/2014 Expresiones Join SQL2 Queremos unir la relaciones Película y Estrellas, usando la condición que el titulo y el año coincidan, debemos modificar la consulta así: Películas FULL OUTER JOIN Estrellas ON titulo = tituloPelicula AND año = añoPelicula; La palabra clave FULL puede ser reemplazada por LEFT o RIGHT en el anterior tipo de outerjoin: d) Películas LEFT OUTER JOIN Estrellas ON titulo = tituloPelicula AND año = añoPelicula; e) Películas RIGHT OUTER JOIN Estrellas ON Titulo = tituloPelicula AND Año = añoPelicula; 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 7 Restricciones en SQL2 La integridad de los datos en una base de datos es un aspecto muy importante a tener en cuenta en la implementación de un diseño. Existen al menos dos formas de mantenerla: a. Incorporando las restricciones en los programas de aplicación (se multiplica el código específico que implementa restricciones en las aplicaciones). b. Incorporando declaraciones al SMBD, formando parte del esquema de la base de datos. SQL2 provee una variedad de técnicas para implementar Restricciones de integridad como parte del esquema de la base de datos. Veamos los diferentes tipos de restricción previstos en SQL: 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 8 4 15/10/2014 Restricciones en SQL2 Declaración de Llaves Es el tipo de restricción más importante en una base de datos. Se prohibe que dos tuplas de una relación coincidan en el atributo declarado como llave. La llave se declara dentro del comando SQL CREATE TABLE. Hay dos formas similares de declarar una llave: usando la cláusula PRIMARY KEY o la cláusula UNIQUE. Hay dos formas de declarar una llave primaria: 1) Se puede declarar un atributo como llave primaria cuando se define el esquema relacional. CREATE TABLE Hospital ( numeroH smallint PRIMARY KEY ... ); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 9 Restricciones en SQL2 2) Se puede agregar al esquema ya declarado, una nueva declaración que defina la llave de la relación: CREATE TABLE Personal ( hospitalNro smallint, codigo smallint, nombre varchar (40), ... PRIMARY KEY (hospitalNro, codigo) ... ); Para utilizar la cláusula UNIQUE basta con reemplazar la palabra PRIMARY KEY por UNIQUE. Tiene la misma importancia de una declaración de llave primaria. Sin embargo, en una tabla puede haber varias declaraciones UNIQUE pero solo una llave primaria. Muchas versiones SQL ofrecen la creación de índices que usan la cláusula UNIQUE para declarar el (o los) atributos (s) que serán llave al mismo tiempo que crea un índice sobre dicho atributo: CREATE UNIQUE INDEX indiceAño ON Películas (año); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 10 5 15/10/2014 Restricciones en SQL2 Integridad Referencial y Llaves Foráneas Un segundo tipo de restricción en el esquema de la base de datos es que los valores de algunos atributos deben ser lógicos. Estamos hablando de la “integridad referencial”, concepto que esta estrechamente relacionado con el de Llave Foránea, que establece que el valor de un atributo puede ser nulo o su valor exista como valor en la llave primaria de otra tabla. La llave foráneas permite implementar relaciones uno a muchos. CREATE TABLE Medico ( hospitalNro smallint, codigo smallint, nombre varchar (40),... CONSTRAINT fkHosp FOREIGN KEY (hospitalNro) REFERENCES Hospital (numeroH) ... ); donde fkHosp es el nombre de la restricción. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 11 Restricciones en SQL2 Declaración de restricciones de la llave foránea En SQL podemos declarar uno o varios atributos como llave foránea, referenciando el (los) atributo(s) de otra relacion (que puede ser la misma relación). Esta declaración trae las siguientes implicaciones: 1. Los atributos referenciados en la segunda relación deben ser declarados como llave primaria de su relacion. 2. Un valor del atributo de la llave foránea en la primera tabla, también debe aparecer en el correspondiente atributo de la segunda relación: restricción de integridad referencial . 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 12 6 15/10/2014 Restricciones en SQL2 Declaración de restricciones de la llave foránea Hay dos formas de declarar llaves foráneas: a. Si la llave foránea es una tributo simple, podemos usar: REFERENCES <tabla> (<atributos>) b. Anexar a la lista de atributos (CREATE TABLE) una o más declaraciones enunciando que un conjunto de atributos son una llave foránea. Indicamos despues la tabla y sus atributos (que son llave primaria). La forma es: FOREING KEY <atributos> REFERENCES <tabla> (<atributos>) Ejemplo: 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 13 Restricciones en SQL2 CREATE TABLE Estudio ( nombreEst CHAR ( 30) PRIMARY KEY, direcciónEst VARCHAR (225), codProductor INT REFERENCES EjecutivosCine (codProductor) ); Una forma alternativa será: CREATE TABLE Estudio ( nombreEst CHAR (30) PRIMARY KEY, direcciónEst VARCHAR (225), codProductor INT, FOREIGN KEY codProductor REFERENCES EjecutivosCine (codProductor) ); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 14 7 15/10/2014 Restricciones en SQL2 Mantenimiento de la Integridad Referencial En SQL se dispone de varias formas de implementar la conservación de las restricciones de integridad referencial. Rechazar las modificaciones que violan la integridad referencial lo cual es la política por defecto en SQL. Las siguientes acciones serán rechazadas por el sistema (error en tiempo de ejecución): Intento de insertar una tupla cuyo valor en la llave foránea no es nulo o no existe como valor de la llave primaria. Intento de actualizar una tupla cuya valor de llave foránea no existe como valor en la llave primaria. La tupla original permanece igual. Intento de eliminar una tupla en la tabla de la llave primaria cuando su componente aparece como valor en la llave foránea de la segunda relación en una o más tuplas. Se rechaza eliminación y se conservan las demás tuplas. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 15 Restricciones en SQL2 Política en cascada Cuando se borran o actualizan tuplas en la tabla que posee la llave primaria, se borran o se actualizan las tuplas relacionadas en la tabla que posee la llave foránea. Política de asignar valor nulo En la cual ante retiros o modificaciones de tuplas en la tabla que posee la llave primaria, se modifican los valores de la tabla que maneja la llave foránea, cambiándolos a NULL. Política de asignar valor por defecto En la cual ante retiros o modificaciones de tuplas en la tabla que posee la llave primaria, se modifican los valores de la tabla que maneja la llave foránea cambiándolos al valor DEFAULT. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 16 8 15/10/2014 Restricciones en SQL2 Veamos la sintaxis: FOREIGN KEY ( a1, , ... , aj) REFERENCES R (K1, ... , Kj) [ON DELETE {SET DEFAULT | SET NULL | CASCADE | NO ACTION}] [ON UPDATE {SET DEFAULT | SET NULL | CASCADE | NO ACTION}] En el ejemplo: CREATE TABLE Estudio ( nombreEst CHAR ( 30) PRIMARY KEY, direcciónEst VARCHAR (225), codProductor INT REFERENCES EjecutivosCine (codProductor) ON DELETE SET NULL ON UPDATE CASCADE ); Las acciones alternativas son SET DEFAULT, SET NULL, CASCADE y NO ACTION. La acción por defecto es (no hacer nada) NO ACTION. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 17 Restricciones en SQL2 Restricciones de los Valores de Atributos Un tercer grupo de restricciones lo constituyen las restricciones que limitan los valores que pueden aparecer en los componentes de algunos atributos. Se pueden expresar como una restricción al atributo dentro de la definición del esquema o, como una restricción de dominio del atributo en cuestión. Algunas de las formas de implementación de este tipo de restricciones se pueden expresar mediante: Restricciones NO NULAS Se asocia a la opción NOT NULL; especifica que no se puede ingresar un valor nulo para el atributo. Ejemplo: codProductor INT NOT NULL, 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 18 9 15/10/2014 Restricciones en SQL2 Restricciones CHECK Basadas en Atributos Se pueden incorporar restricciones más complejas a la declaración de un atributo mediante la palabra clave CHECK, seguida de una condición entre paréntesis. En la práctica es una limitación simple sobre valores, aunque en teoría la condición puede ser cualquier cosa que le siga al where en una consulta SQL. Una restricción CHECK basada en atributo se verifica siempre que una tupla cualquiera reciba en ella un nuevo valor (actualización, o inserción). La restricción CHECK basada en atributo NO se verifica necesariamente, si una modificación de la BD no cambia el valor del atributo al cual se asocia la restricción; esta limitación puede hacer que se viole la restricción. Bases de Datos I - Mauricio E. Fernández N 15/10/2014 19 Restricciones en SQL2 Sintaxis: CHECK (Condición de búsqueda) Ejemplos:Suponga que se requiere que el codProductor sea de al menos 6 dígitos en la relación Estudio: codProductor INT REFERENCES EjecutivosCine (codProductor) CHECK (codProductor >=100000); Ejemplo: verificar el sexo en las relación EjecutivosCine que tenga un carácter y que pueda tomar los siguientes valores `F´ o `M´: sexo CHAR (1) CHECK (sexo IN ( `F´,`M´) ) CREATE TABLE Hospital ( ... camas smallint CHECK (camas < 1000), ... ); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 20 10 15/10/2014 Restricciones en SQL2 CREATE TABLE Hospital ( ... camas smallint CHECK (camas <= (SELECT count (*)/10 FROM Personal) ) ... ); CREATE TABLE Paciente ( ... cuota decimal (8,2), nroFarmacia smallint, consuSinCargo smallint ... CHECK ((cuota between 50 and 500) and (nroFarmacia between 10 and 100) and (consuSinCargo between 1 and 20) ) ... ); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 21 Restricciones en SQL2 CREATE TABLE Medico ( ... especial char (5) CHECK ( (especial IN (‘clini’, ’pedia’, ’traum’, ’obste’, ’cardi’, ‘otras’ ) ) ... ); Restricciones de Dominios También se puede restringir los valores de un atributo al declarar un dominio con una restricción similar y declarando que el dominio es el tipo de dato para el atributo. En SQL2 se usa la palabra reservada VALUE para referirse a un valor del dominio. Ejemplo: declarar un domino, dominioSexo con los caracteres `F´ y `M´ como unión de valores permitidos: CREATE DOMAIN dominioSexo CHAR (1) CHECK (VALUE IN (`F´, M´) ); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 22 11 15/10/2014 Restricciones en SQL2 Por lo tanto, el definir el atributo sexo en la relación EjecutivosCine puedo hacerlo así: sexo dominioSexo, Ejemplo: Crear un dominio para el atributo codProductor número de al menos 6 dígitos en la relación Estudio : CREATE DOMAIN dominioProductor INT CHECK (VALUE >= 100000); Y luego al reescribir la declaración de codProductor: codProductor dominioProductor REFERENCES EjecutivosCine (codProductor) Obtenemos la restricción deseada. Ejemplos: CREATE DOMAIN clave AS integer CHECK (Value > 30) CHECK (Value is NOT NULL); CREATE DOMAIN color AS char (10) DEFAULT ´Sin color´ CHECK (Value IN (´Sin color´, ´Azul´, Ámarillo´, ´Rojo´, ´Negro´)); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 23 Restricciones en SQL2 Restricciones Globales Corresponden al tipo de declaración de restricciones más complejas; se refieren a las relaciones entre varios atributos o incluso a relaciones diversas. Son de dos tipos: Restricciones CHECK basadas en tuplas, que limitan cualquier aspecto de las tuplas de una sola relación. Aserciones, son aquellas que pueden incluir relaciones enteras o algunas variables de tuplas que abarcan la misma relación. Restricciones CHECK Basadas en Tuplas Para declarar una restricción sobre tuplas de una tabla, al definirla (CREATE TABLE) podemos agregar a la lista de atributos y a las declaraciones de llaves o llaves foráneas la palabra clave CHECK seguida de una condición entre paréntesis. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 24 12 15/10/2014 Restricciones en SQL2 La restricción CHECK basada en tuplas se evalúa cada vez que se realice una inserción o una actualización sobre la tabla R. Si la condición menciona alguna relación en una subconsulta, y si una modificación de esta relación vuelve falsa la condición en alguna tupla de R, la verificación no mostrará ese cambio. Ejemplo: CREATE TABLE EstrellasPelicula ( nombre CHAR (30) UNIQUE, dirección VARCHAR (25) , sexo CHAR (1), fechaNacmto DATE, CHECK (sexo = `F´ OR nombre NOT LIKE `Sra.%´ ); Se recomienda utilizar aserciones para definir restricciones más complejas. Bases de Datos I - Mauricio E. Fernández N 15/10/2014 25 Restricciones en SQL2 Aserciones Una aserción es una restricción a la base de datos que restringe el contenido de la base de datos como un todo. Al igual que en las rectricciones check, una restricción se especifica como una condición de búsqueda. Pero se diferencia en que la condición de la aserción puede restringir el contenido de varias tablas y las relaciones entre ellas. Por esta razón la aserción se especifica como parte de la definición del esquema de la base de datos, por medio de la instrucción SQL2 CREATE ASSERTION. Su forma general es: CREATE ASSERTION nombreRestricción CHECK (condición de búsqueda); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 26 13 15/10/2014 Restricciones en SQL2 CREATE TABLE Orden ( nOrden INTEGER NOT NULL, fechaOrden DATE NOT NULL, codCliente INTEGER NOT NULL, Producto CHAR (5), Cantidad INTEGER NOT NULL, valorOrden NUMBER (10,2)); CREATE TABLE Cliente ( nroCliente INTEGER NOT NULL, nomEmpresa VARCHAR (25) NOT NULL, direccionCli VARCHAR (25) NOT NULL, limiteCredito NUMBER (10,2)); Suponga que queremos restringir el contenido de las base de datos tal que el total de las ordenes para cualquier cliente no puede exceder el límite de su crédito: CREATE ASSERTION limiteDelCredito CHECK ( (Cliente. nroCliente = Orden.codCliente) AND (sum (valorOrden ) <= límiteCredito )); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 27 Restricciones en SQL Ejemplo: CREATE ASSERTION presidentesRicos CHECK (NOT EXISTS (SELECT * FROM Estudio, EjecutivosCine WHERE Estudio.codProductor = EjecutivosCine. codProductor AND ingresoNeto < 10000000) ); De esta forma la restricción se cumple (es verdadera) cuando la consulta sea vacía. Ejemplo: CREATE ASSERTION totalSalarios CHECK (((SELECT sum (sueldo) FROM Personal) + (SELECT sum (sueldo) FROM Medico)) < 100000000); 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 28 14 15/10/2014 Disparadores en SQL Los disparadores, llamados reglas Evento-Condición-Acción (o siglas ECA), difieren de las restricciones previamente discutidas en tres formas: 1. Los triggers solo son probados cuando ocurren ciertos eventos, especificado por el programador de la BD. Eventos permitidos: son inserciones, borrados, actualizaciones y el fin de una transacción. 2. En lugar de prevenir inmediatamente el evento que activa la acción, un trigger prueba una condición. Si esta no se satisface, entonces no ocurre nada en el trigger en respuesta al evento. 3. Si la condición del trigger se cumple, la acción definida con el triggers es realizada por el DBMS. La acción puede impedir que ocurra el evento, o podría deshacer el evento (como borrar una tupla insertada). La acción podrá ser cualquier secuencia de operaciones sobre la base de datos. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 29 Disparadores en SQL2 La base de datos es incapaz de programarse para especificar: • Cuando verificar una restricción, • Que hacer exactamente cuando se verifica la restricción. Un trigger o disparador tiene 3 partes: • Un evento (ejemplo: actualizar un atributo) • Una condición (ejemplo: una condición a evaluar) • Una acción (borrado, actualización, inserción) NOTA: los triggers pueden causar efectos en cascada. ¡Los vendedores de bases de datos no esperaron estándares con disparadores! 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 30 15 15/10/2014 Disparadores en SQL Características de los Triggers 1. La acción puede ser ejecutada antes, después o durante el evento definido en el trigger. 2. La acción puede referirse a valores viejos o nuevos que se insertaron, borraron o actualizaron en el evento que dispara la acción del trigger. 3. Los eventos de actualización pueden especificar un atributo particular o un conjunto de atributos. 4. Una condición puede ser especificada con una cláusula WHEN, y la acción solo se ejecutará si la regla es activada y se cumple la condición cuando el evento definido en el trigger ocurre. 5. El programador tiene la opción de especificar que la acción sea realizada: a) Una vez en cada tupla modificada b) Una vez en todas las tuplas que cambian en la operación Bases de Datos I - Mauricio E. Fernández N 15/10/2014 31 Disparadores en SQL Para crear un trigger se usa el comando CREATE TRIGGER. Veamos su sintaxis: CREATE [OR REPLACE] TRIGGER <nombreTrigger> BEFORE | AFTER --Tiempo del evento { {INSERT | UPDATE} [OF columna(s) ] |DELETE } ON <nombreTabla> -- Eventos disparadores FOR EACH ROW --Tipo de Trigger [WHEN (<condición>) ] -- Restricción al Trigger <Bloque PL/SQL> --Cuerpo del trigger END; -- Fin del disparador 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 32 16 15/10/2014 Disparadores en SQL Ejemplo: Trigger a nivel de tupla CREATE TRIGGER No-Baja-Precios AFTER UPDATE OF precio ON Producto REFERENCING OLD AS OldTuple NEW AS NewTuple WHEN (OldTuple.precio > NewTuple.precio) UPDATE Producto SET precio = OldTuple.precio WHERE nombre = NewTuple.nombre FOR EACH ROW 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 33 Disparadores en SQL Trigger a nivel de Instrucción CREATE TRIGGER mantiene_precio-promedio INSTEAD OF UPDATE OF precio ON Producto REFERENCING OLD_TABLE AS TablaOld NEW_TABLE AS TablaNew WHEN (1000 < (SELECT AVG (precio) FROM ((Producto EXCEPT TablaOld) UNION TablaNew)) DELETE FROM Producto WHERE (nombre, precio, empresa) IN TablaNew; INSERT INTO Producto (SELECT * FROM TablaOld) 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 34 17 15/10/2014 Disparadores en SQL Sea la relación EjecutivosCine (nombre, dirección, codProductor, ingresoNeto) Vamos a aplicar un disparador que opere sobre actualizaciones al atributo ingresoNeto. El efecto de esta regla es restaurar el valor inicial por cualquier intento de reducir el ingreso neto de un ejecutivo: 1) CREATE OR REPLACE TRIGGER ingresoNetoTrigger 2) AFTER UPDATE OF ingresoNeto on EjecutivosCine 3) REFERENCING 4) OLD AS oldTuple 5) NEW AS newTuple 6) WHEN (oldTuple.ingresoNeto > newTuple.ingresoNeto) 7) UPDATE EjecutivosCine SET ingresoNeto = Oldtuple.ingresoNeto WHERE codProductor = Newtuple.codProductor 8) FOR EACH ROW; 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 35 Disparadores en SQL A continuación mostraremos otras alternativas: A la cláusula AFTER: { BEFORE | INSTEAD OF } En reemplazo del UPDATE: { INSERT | DELETE }. La acción puede ser cualquier número de intrucciones separadas por punto y coma. Cuando el evento del trigger es una actualización, entonces habrá una tupla vieja y otra nueva, los cuales son las tuplas antes y después de la actualización: OLD AS y NEW AS. Si se omite (FOR EACH ROW) entonces el trigger a nivel de tupla se convierte en un trigger a nivel de instrucción, el cual se ejecuta una vez por cada instrucción que genere uno o más eventos definidos para el trigger. En un trigger a nivel de instrucción nos tendremos que referir al conjunto de tuplas viejas y nuevas, (declaraciones tales como OLD_TABLE AS ViejosValores y NEW_TABLE AS NuevosValores. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 36 18 15/10/2014 Disparadores en SQL Ejemplo. Se desea prevenir que el promedio del ingresoNeto de los ejecutivos del cine caiga por debajo de los $5.000.000. Esta restricción podrá ser violada por una inserción, retiro o actualización del atributo ingresoNeto en la relación EjecutivosCine. Se necesita un trigger para cada uno de estos eventos. En el ejemplo siguiente se muestra el trigger para el evento de una actualización: 1) CREATE OR REPLACE TRIGGER promedioIngresoNetoTrigger 2) AFTER UPDATE OF ingresoNeto ON EjecutivosCine 3) REFERENCING 4) OLD TABLE AS viejosDa 5) NEW TABLE AS nuevosDa 6) WHEN (5 000 000 >= 7) (SELECT AVG (ingresoNeto) FROM ((EjecutivosCine EXCEPT viejosDa) UNION nuevosDa))) 8) DELETE FROM EjecutivosCine WHERE (nombre, dirección, codProductor, ingresoNeto) IN nuevosDa; 9) INSERT INTO EjecutivosCine (SELECT * FROM viejosDa); 10) END. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 37 Disparadores en SQL En el ejemplo siguiente se muestra el trigger a nivel de instrucción para el evento de un borrado: 1) CREATE OR REPLACE TRIGGER TriggerPromIngreNetoRet 2) AFTER DELETE OF ingresoNeto ON EjecutivosCine 3) REFERENCING OLD TABLE AS tablaVieja 4) WHEN ((SELECT AVG (ingresoNeto) FROM (EjecutivosCine)) <= 5 000000 ) 5) INSERT INTO EjecutivosCine (SELECT * FROM tablaVieja); 6) END. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 38 19 15/10/2014 Disparadores en SQL Se recomienda seguir las siguientes reglas para la definición de triggers de mantenimiento de integridad: Identifique operaciones y tablas críticas para la restricción de integridad Por cada una de tales tablas verifique Si la restricción puede ser verificada a nivel de fila entonces Si la fila verificada es modificada en el trigger entonces Use un trigger de fila con before De lo Contrario Use un trigger de fila con After De lo Contrario Use un trigger de instrucción con After Los triggers no son exclusivamente utilizados para mantener la integridad. También se puede usar para: Propósitos de monitoreo de acceso de usuarios y modificaciones a ciertas tablas Acciones de seguridad sobre tablas 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 39 Ejercicio en SQL Sea la siguiente base de datos: Empleado : nDI(numérico), nombre (10 caracteres), salario (numérico), numDep (10 caracteres), sexo (1 carácter “M” o “F”) Departamento: numDep (10 caract.), nombre (10 caract.), presupto (numérico) Utilizar SQL para crear las tablas de la base de datos, incluyendo las restricciones de integridad que se solicitan. Crear todas las tablas, especificando en cada caso las claves primarias y foráneas. Especificar en la tabla Empleado que: a) el salario este en el rango 1,500.000 a 5.000.000, b) el nombre y salario no deben ser nulos. Especificar el sexo del empleado creando un dominio. En la tabla Empleado, especificar que si un departamento es retirado en la tabla Departamento, se eliminan los registros en Empleado. Si el departamento cambia de numDep, sus registros en Empleado serán actualizados. El total del presupto de un Departamento debe ser mayor o igual al 50% de la suma de los salarios de los empleados que laboran en dicho departamento. Diseñar un disparador que al insertar un nuevo empleado, automáticamente actualice el presupuesto total del Departamento al que el empleado pertenece, añadiéndole el salario devengado por el nuevo empleado. Diseñar un disparador que al modificar el salario de un empleado, actualice automáticamente el presupuesto total del Departamento. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 40 20 15/10/2014 Disparadores en SQL Considere las siguientes relaciones: Mascota (nroChip, nombre, raza, peligrosidad, fechaNacimto, dIP) Propietario (dIP, fechaAlta) Persona (dIP, fechaNacimto, lugarNacimto, nombre, direccion) Indique cómo definiría las siguientes restricciones de integridad en SQL: 1. 2. 3. 4. 5. 6. No puede haber dos mascotas con el mismo número de chip Todo propietario es una persona El campo peligrosidad sólo puede tomar los valores 0 (falso) 1 ( verdadero) Un propietario pueden serlo de varias mascotas Las mascotas no tienen porque vivir en la misma dirección que sus propietarios Se quiere almacenar más información sobre las razas de los animales de forma que , para cada raza, se almacena un identificador (para distinguir una raza de todas las demás), el nombre de la raza, el tipo (perro, gato, reptil, equino), el color , el tipo de pelo (largo, corto), y su peligrosidad (0 para las no peligrosas y 1 para las peligrosas) 7. No todas las personas deben ser propietarias de mascotas 8. Sólo pueden ser propietarios de mascotas las personas mayores de 18 años 9. Cuando una mascota muere (se eliminan sus datos de la tabla mascota), tiene que dejar de estar asociada a su propietario 10. Toda mascota tiene que tener un nombre 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 41 SQL Embebido El lenguaje huésped manipula variables, valores, punteros . El SQL manipula relaciones. No hay construcciones en el lenguaje huésped para la manipular relaciones. ¿Por qué no utilizar solamente un lenguaje ? Olvidar el SQL: ¡definitivamente no una buena idea! El SQL no puede hacer todo que el lenguaje huésped puede hacer. Hay dos razones por las que podríamos utilizar SQL desde un lenguaje huésped: Hay consultas que no se pueden formular con SQL puro (por ejemplo, las consultas recursivas) . Para realizar esas consultas necesitamos un lenguaje de huésped de mayor poder expresivo que el SQL . Si queremos acceder a una base de datos desde una aplicación que está escrita en el lenguaje del huésped (p.e. un sistema de reserva de tiquetes con una interface gráfica escrita en Java y donde la información sobre los tiquetes está almacenada en una base de datos que puede accederse utilizando SQL embebido). 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 42 21 15/10/2014 SQL Embebido Un programa que utiliza SQL embebido en un lenguaje de host consiste en instrucciones del lenguaje del host e instrucciones de SQL embebido. Cada instrucción de SQL Embebido empieza con las palabras claves EXEC SQL. Estas instrucciones se transforman en instrucciones del lenguaje del host mediante un precompilador (que habitualmente inserta llamadas a rutinas de librerías que ejecutan los variados comandos de SQL). Cuando ejecutamos una instrucción SELECT vemos que el resultado de las consultas es un conjunto de tuplas . La mayoría de los lenguajes huésped no están diseñados para operar con conjuntos, de modo que necesitamos un mecanismo para acceder a cada tupla única del conjunto de tuplas devueltas por una instrucción SELECT. Este mecanismo puede ser proporcionado declarando un cursor . Tras ello, podemos utilizar el comando FETCH para recuperar una tupla y apuntar el cursor hacia la siguiente tupla. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 43 SQL Embebido Lenguaje Huesped + SQL Embebido Preprocesador Preprocessor Lenguaje Huesped + llamado a funciones Compilador del Lenguaje Huesped Host language compiler Programa en Lenguaje Huesped 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 44 22 15/10/2014 SQL Embebido El SQL directo es raramente utilizado! SQL necesita estar embebido en un lenguaje de propósito general para permitir: IGU Flujo de control Generar SQL dinámico basado en las entradas del usuario. Los comandos SQL pueden ser llamados desde un lenguaje huésped (como C/C++ o Java) o desde lenguajes de etiquetado (como PHP o Ruby). Una respuesta a una consulta es una bolsa de registros – con un numero arbitrario de muchos registros! En la mayoría de lenguajes no hay una estructura de datos como esta. Este problema se denomina impedance mismatch El SQL estándar soporta los cursores para el manejo de esto. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 45 SQL Embebido Interface: SQL / Lenguaje Anfitrion Los valores son pasados con variables compartidas. Los dos puntos (:) preceden variables compartidas cuando ocurren dentro de una declaración SQL. EXEC SQL precede cada declaración de SQL en el lenguaje anfitrión. La variable SQLSTATE proporciona mensajes de error y el estado de los informes (ejemplo, 00000 dice que la operación fue terminada sin problema). EXEC SQL BEGIN DECLARE SECTION; char productName[30]; EXEC SQL END DECLARE SECTION; 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 46 23 15/10/2014 SQL Embebido Uso de Variables Compartidas Void insercionSimple() { EXEC SQL BEGIN DECLARE SECTION; char nombProducto[20], fabrica[30]; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION; /* Aquí se obtienen los valores para nombProducto y fabrica de alguna manera */ EXEC SQL INSERT INTO Producto (nombre, empresa) VALUES (:nombProducto, :fabrica); } 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 47 SQL Embebido Instrucción SELECT para escoger una fila Void traerPrecio() { EXEC SQL BEGIN DECLARE SECTION; char nombreProducto[20], fabrica[30]; integer precioT; char SQLSTATE[6]; EXEC SQL END DECLARE SECTION; /* leer el valor de nombreProducto */ EXEC SQL SELECT precio INTO :precioT FROM Producto WHERE Producto.nombre = :nombreProducto; /* imprimir valor de precio */ } 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 48 24 15/10/2014 SQL Embebido Cursores El término cursor se refiere a una estructura de control utilizada para el recorrido (y potencial procesamiento) de los registros del resultado de una consulta. Un cursor se usa para el procesamiento individual de tuplas devueltas por el SMBD para una consulta. Se necesita porque muchos lenguajes de programación sufren de impedance mismatch. Por norma general los lenguajes de programación son procedurales y no disponen de ningún mecanismo para manipular conjuntos de datos en una sola instrucción. Por ello, las filas deben ser procesadas de forma secuencial por la aplicación. Un cursor puede verse como un iterador sobre la colección de filas que hay en el set de resultados. Existen sentencias SQL que no requieren del uso de cursores. Ello incluye la sentencia Insert, así como la mayoría de formas del Update o el Delete. Incluso una sentencia Select puede no requerir un cursor si se utiliza en la variante de SELECT...INTO, ya que esta variante sólo devuelve una fila. Bases de Datos I - Mauricio E. Fernández N 15/10/2014 49 SQL Embebido Cursores Un cursor es creado utilizando la sentencia DECLARE CURSOR. Es obligatorio asignarle un nombre. DECLARE cursor_name CURSOR FOR SELECT ... FROM ... Antes de ser utilizado, el cursor debe ser abierto con una sentencia OPEN. Como resultado de esta sentencia, el cursor se posiciona antes de la primera fila del set de resultados. OPEN cursor_name La posición de un cursor de recorrido puede especificarse de forma relativa a la posición actual del cursor o de forma absoluta a partir del principio del set de resultados. FETCH [ NEXT | PRIOR | FIRST | LAST ] FROM cursor_name FETCH ABSOLUTE n FROM cursor_name FETCH RELATIVE n FROM cursor_name 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 50 25 15/10/2014 SQL Embebido Cursores EXEC SQL DECLARE nombreCursor CURSOR FOR SELECT …. FROM …. WHERE …. ; EXEC SQL OPEN nombreCursor; while (true) { EXEC SQL FETCH FROM nombreCursor INTO :variables; if (NO_MORE_TUPLES) break; /* Se trabaja con los valores */ } EXEC SQL CLOSE nombreCursor; 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 51 SQL Embebido Cursores Obtenga los nombres de los estudiantes que practican natación, en orden alfabético: EXEC SQL DECLARE DeporNataciónCur CURSOR FOR SELECT nombre FROM Estudiante JOIN EstudXDeporte ON Estudiante.codigoE = EstudXDeporte.codEstud AND EstudXDeporte.deporte = ‘Natación’ ORDER BY nombre; (EXEC SQL OPEN DeporNataciónCur; while true) { EXEC SQL FETCH FROM DeporNataciónCur INTO :nombreCur; if (NO_MORE_TUPLES) break; /* Los : en :nombreCur se refiere a una variable declarada en el programa */ } EXEC SQL CLOSE DeporNataciónCur; 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 52 26 15/10/2014 SQL Embebido Más sobre Cursores Los cursores pueden modificar una relación así como se lee. Podemos determinar el orden en el cual el cursor traerá las tuplas por la palabra clave ORDER BY en la consulta SQL. Los cursores pueden proteger contra cambios a relaciones subyacentes. El cursor puede tener movimiento en algún sentido: puede ir adelante, hacia atrás +n, - n, ABS (n), ABS (- n). 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 53 SQL Dinámico Hemos considerado hasta ahora solamente embeber estático en lenguajes de programación. SQL El SQL estático embebido está muy bien para aplicaciones fijas cuando deseamos ejecutar una consulta SQL específica desde un lenguaje de programación, p.e., un programa que es utilizado por las agencias de viajes para reservar un asiento de una línea aérea. ¿Qué si la consulta SQL que deseamos embeber no se conoce por adelantado en tiempo de compilación? Por ejemplo, el código que implementa una base de datos toma una consulta del usuario en tiempo de ejecución y la suministra a la base de datos. El SQL dinámico permite que la consulta sea especificada en tiempo de ejecución. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 54 27 15/10/2014 SQL Dinámico Dos declaraciones especiales del SQL embebido: PREPARE convierte una cadena de caracteres en una consulta SQL. EXECUTE ejecuta esa consulta Ejemplo de USAGE EXEC SQL BEGIN DECLARE SECTION; char datoConsulta [MAX_QUERY_LENGTH]; EXEC SQL END DECLARE SECTION; /* Se lee el texto del usuario en el arreglo datoConsulta*/ EXEC SQL PREPARE q FROM :datoConsulta; EXEC SQL EXECUTE q; /* programa que lee una consulta SQL y la ejecuta */ 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 55 Arquitectura POSTGRES El siguiente gráfico muestra de forma esquemática las entidades involucradas en el funcionamiento normal del gestor de bases de datos: PostgreSQL está basado en una arquitectura cliente-servidor. El programa servidor se llama postgres y entre los muchos programas cliente tenemos, por ejemplo, pgaccess (un cliente gráfico) y psql (un cliente en modo texto). Un proceso servidor postgres puede atender exclusivamente a un solo cliente; es decir, hacen falta tantos procesos servidor postgres como clientes haya. El proceso postmaster es el encargado de ejecutar un nuevo servidor para cada cliente que solicite una conexión. Se llama sitio al equipo anfitrión (host) que almacena un conjunto de bases de datos PostgreSQL. En un sitio se ejecuta solamente un proceso postmaster y múltiples procesos postgres. Los clientes pueden ejecutarse en el mismo sitio o en equipos remotos conectados por TCP/IP. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 56 28 15/10/2014 Arquitectura POSTGRES El administrador Postgres Terminada la instalación, en el S.O. se creará el usuario postgres, y en PostgreSQL se habrá creado un usuario con el mismo nombre. Él es el único usuario existente en la base de datos y será el único que podrá crear nuevas bases de datos y nuevos usuarios. Normalmente, al usuario postgres del S.O. no se le permitirá el acceso desde un shell ni tendrá contraseña asignada, por lo que debemos convertirnos en el usuario root, para después convertirnos en el usuario postgres y realizar tareas en su nombre. Se deben decrear los usuarios necesarios para operar la instalación de PostgreSQL, e ingresar, lo menos posible, con el usuario postgres. Es posible restringir el acceso a usuarios o a direcciones IP modificando las opciones del archivo de configuración (pg_hba.conf). 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 57 Arquitectura POSTGRES Para entender lo básico de la arquitectura del s/ma Postgres, debemos entender como interactúan las partes de Postgres. En la Jerga de bases de datos, Postgres usa un modelo cliente/servidor conocido como "proceso por usuario". Una sesión Postgres consiste en los siguientes procesos cooperativos (programas): un proceso supervisor (postmaster), la aplicación sobre la que trabaja el usuario (frontend) (p.e. el programa psql), y uno o más servidores de bases de datos en segundo plano (el mismo proceso postgres). Un único postmaster controla una colección de bases de datos dadas en un host. Por ello una colección de bases de datos se suele llamar instalación o un sitio. Las aplicaciones de frontend que quieren acceder a una determinada base de datos dentro de una instalación hacen llamadas a la librería. La librería envía peticiones de usuario a través de la red al postmaster (establece una conexión), el cual en respuesta inicia un nuevo proceso en el servidor (backend) y conecta el proceso de frontend al nuevo servidor. A partir de este punto, el proceso de frontend y el servidor en backend se comunican sin la intervención del postmaster. Aunque, el postmaster siempre se está ejecutando, esperando peticiones, los procesos de frontend y de backend vienen y se van. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 58 29 15/10/2014 Arquitectura POSTGRES La librería libpq permite a un único proceso en frontend realizar múltiples conexiones a procesos en backend. Aunque, la aplicación frontend todavía es un proceso en un único thread. Una implicación de esta arquitectura es que el postmaster y el proceso backend siempre se ejecutan en la misma máquina (el servidor de base de datos), mientras que la aplicación en frontend puede ejecutarse desde cualquier sitio. Debe tener esto en mente, porque los archivos que pueden ser accedidos en la máquina del cliente pueden no ser accesibles (o sólo pueden ser accedidos usando un nombre de archivo diferente) en la máquina del servidor de base de datos. Tenga en cuenta que los servicios postmaster y postgres se ejecutan con el identificador de usuario del "superusuario" Postgres. Note que el superusuario Postgres no necesita ser un usuario especial (ej. un usuario llamado "postgres"). De todas formas, el superusuario Postgres definitivamente no tiene que ser el superusuario de Unix ("root")! En cualquier caso, todos los archivos relacionados con la base de datos deben pertenecer a este superusuario Postgres. 15/10/2014 Bases de Datos I - Mauricio E. Fernández N 59 30