BLOQUE 3 (IV): LENGUAJE SQL Vistas 3.21.- INTRODUCCIÓN Una view es una tabla derivada (de una instrucción SELECT), a la que se le asigna un nombre. Con las vistas se trabaja de la misma forma que con las tablas de la base de datos, aunque no tiene existencia física (ficheros .dat y .idx), sin embargo es un objeto permanente de la base de datos que se obtiene cada vez que se hace referencia a la vista. Aunque las vistas no tienen asociados ficheros físicos, si forman parte de las tablas del catálogo de la base de datos (systables, syscolumns, systabauth, sysviews, sysdepend, syssynonyms). Algo importante que se debe tener en cuenta es que una view no tiene rowid, un número diferente asignado a cada una de sus filas. La utilización de vistas es importante por varios motivos: - Presentan los datos de las tablas en una estructura que coincide con el concepto que posee el usuario de la información almacenada en la base de datos. - Prohíben el acceso a datos confidenciales: si en una tabla existen datos a los que no deben tener acceso determinados usuarios, se puede construir una vista en la que dichos datos no aparecen y dichos usuarios tendrán permiso para trabajar con la vista y no con la tabla, para ellos es como si esos datos no existieran. Se pueden limitar los accesos a determinadas columnas o a determinadas filas. - Facilitan la realización de consultas largas y complicadas (consultas con varios enlaces entre tablas y varias subconsultas), ya que se pueden crear una o varias vistas y después realizar consultas simples sobre ellas, ahorrando tiempo y posibles equivocaciones. - Aumentan la independencia de los programas con respecto a los datos: supongamos que cambia la situación de una determinada empresa y es necesario cambiar la estructura de una tabla (cambiando los nombres de sus columnas o dividiendola en dos tablas), esta situación supondría modificar las sentencias SQL que se refieran a la tabla original. Pero si definimos una vista sobre la tabla antigua podremos representar la nueva situación y seguirán valiendo los programas que utilizaban la estructura antigua. 3.22.- CREACION Y BORRADO DE UNA VIEW La creación de una view se realiza mediante la instrucción: CREATE VIEW nombre_view [(columnas)] AS instrucción_select [WITH CHECK OPTION] WITH CHECK OPTION: se emplea cuando la view se utiliza para actualizar las tablas originales que componen la view, si solamente vamos a realizar consultas sobre la vista no es necesaria esta cláusula. Una vez que hemos creado una vista sobre una tabla, podemos realizar consultas sobre la vista, que a su vez dichas consultan se pueden almacenar como nuevas vistas. No se puede modificar la estructura de las views, si fuera necesario hacer modificaciones habría que borrar la view existente y crear una nueva con la estructura deseada. Para borrar una view se utiliza la instrucción: DROP VIEW nombre_view Si una vista V2 está basada en otra vista V1, cuando se borra la vista V1 desaparece la vista V2. 3.23.- ACTUALIZACION DE VIEWS ACTUALIZACIÓN DE UNA VIEW DERIVADA DE UNA SOLA TABLA Para que se pueda actualizar una view es necesario que cumpla las siguientes restricciones: - - La lista select de la instrucción SELECT que define la view no puede contener expresiones, (un valor agregado también es una expresión), ya que no es posible saber que fila de la tabla base es la que está afectada por el cambio. La instrucción SELECT que define la view tampoco puede incluir las cláusulas DISTINCT, GROUP BY y HAVING. Las columnas de la tabla base que no estén incluidas en la view no pueden estar definidas como NOT NULL. (CUIDADO NO ES CIERTO). La view debe incluir la clave primaria de la tabla base o las columnas que identifiquen univocamente cada tupla en la tabla. (CUIDADO NO ES CIERTO). ACTUALIZACIÓN DE UNA VIEW DERIVADA DE DOS TABLAS (TODO CON RESERVAS) Se aplican las mismas restricciones que en el caso anterior, salvo la última (inclusión de la clave primaria) , ya que al intervenir dos tablas, se realiza una operación de join y la instrucción SELECT devolverá las tuplas que cumplan la condición de enlace y se podrán dar los siguientes casos: - - Si la relación es unaria (a cada tupla recuperada de la primera tabla base le corresponde una sola tupla de la segunda tabla base), estamos ante un enlace entre las claves primarias de ambas tablas. Si la relación es n-aria (a una tupla de la primera tabla base le corresponden una o mas tuplas de la segunda tabla base, estamos ante un enlace entre la clave primaria de la primera tabla y la clave referencial de la segunda. Estos dos casos implican resultados diferentes en las operaciones de actualización , si llamamos A y B a las partes izquierda y derecha de un join: a) Para el caso de un join con relación entre claves primarias: . INSERT: si existe la clave en A y no en B o viceversa: . Los datos del que existen deben coincidir, sino no se insertaría. . INSERT sobre la tabla que no existe. . DELETE: si existen en ambas tablas, se borran. . UPDATE: si existen en ambas tablas se actualizan, en caso de no existir se procude un INSERT. b) Si estamos ante un join entre clave primaria en A y clave referencial en B: . INSERT: . Si no existe una clave primaria para ninguno de A y B, se produce un INSERT en ambas tablas. . Si existe clave de A que es primaria, sus datos deben coincidir. . Si existe clave de B que es referencial: - La(s) columna(s) de B que establezcan el join debe(n) de ser nula(s). - Los demás datos deben coincidir. - UPDATE de la(s) columna(s) de join al valor de la clave primaria de A. . DELETE: No se puede borrar A. . Si la(s) columna(s) del join en B está(n) definida(s) como NOT NULL, se produce DELETE de B. . Si la(s) columna(s) del join en B admiten nulos, se pone(n) a nulos (borrado lógico). . UPDATE: no se puede actualizar A. . Si existe B, se produce UPDATE sobre B. ACTUALIZACIÓN DE UNA VIEW DERIVADA DE MAS DE DOS TABLAS (TODO CON RESERVAS) Se descompone la view en sus joins, igual que en el caso de view derivada de dos tablas y se aplican las reglas ya definidas con la restricción en este caso de que una tabla mediante su clave referencial no puede enlazar dos tablas mediante sus claves primarias. Pero una tabla con clave primaria sí puede enlazar dos tablas mediante las claves referenciales de éstas. Al resultado de cada join se le aplicará el siguiente join. ACTUALIZACIÓN DE UNA VIEW DERIVADA DE OTRA VIEW (TODO CON RESERVAS) Si la view que queremos actualizar se deriva de otra view que procede de una sola tabla, se aplican las mismas restricciones que en 7.7.1. Si la view que queremos actualizar y/o la view base incluyen algún join (enlace con otra tabla), se aplican las restricciones de actualización de views derivadas de más de una tabla. 3.24.- SINONIMOS Se denomina sinónimo a un nombre alternativo que se puede asignar a una tabla de la base de datos, de manera que se pueden utilizar indistintamente el nombre de la tabla y el sinónimo. La creación de sinónimos se realiza mediante la instrucción: CREATE SYNOMYM sinónimo FOR tabla Para una misma tabla se pueden crear todos los sinónimos que deseemos y una vez creados nos podemos referir a dicha tabla por su nombre o por cualquiera de los sinónimos indistintamente. Cuando se crea un sinónimo, pasa a formar parte del catálogo de la base de datos en la tabla syssynonyms, ocupando una nueva línea en dicha tabla. Los sinónimos persisten en la base de datos hasta que son borrados mediante la instrucción: DROP SYNONYM sinónimo La diferencia fundamental entre un sinónimo y un alias es que el sinónimo persiste en la base de datos hasta que se elimina ejecutando la instrucción DROP SYNONYM sinónimo, mientras que un alias solamente es válido durante la ejecución de la instrucción SELECT que lo crea. 3.25.- LENGUAJE DE CONTROL DE ACCESO A DATOS (DCL) El lenguaje de control de acceso a datos es un sublenguaje del SQL que se ocupa de conceder y retirar permisos a los usuarios sobre la base de datos, las tablas y las columnas, también se ocupa de gestionar la concurrencia de usuarios sobre los datos de la base de datos. Por tanto el DCL se encarga de: - Permisos Bloqueos PERMISOS En el diseño de una base de datos debe quedar determinado que usuarios van a tener acceso, a que datos acceden y que tipo de operaciones pueden realizar. Podemos considerar dos niveles de control de acceso: 1.- Niveles de acceso a los datos: existen tres niveles distintos: 1.a.- Acceso a la base de datos, delimitando: - Los derechos de uso de instrucciones de definición de datos (DDL). - La manipulación de los datos de la base de datos, instrucciones (QL y DML) - La posibilidad de establecer permisos sobre tablas, columnas, etc (DCL). - Activar el tratamiento de transacciones. 1.b.- Acceso a tablas, referido al acceso a sus datos en instrucciones de recuperación o modificación de cualquier tupla de la tabla, modificando su esquema añadiendo columnas o atributos y creando índices. 1.c.- Acceso a columnas de una tabla, que afecta a la consulta (SELECT) y modificación (UPDATE) de columnas específicas de cada tupla de una tabla. 2.- Niveles de acceso respecto a usuarios, también existen tres niveles: 2.a.- DBA, este usuario es el administrador de la base de datos, y tiene un acceso absoluto a todos los niveles de datos, incluyendo el control sobre el tratamiento de transacciones. Un usuario DBA puede conceder o retirar cualquier permiso a otro usuario. El creador de una base de datos se convierte automáticamente en usuario DBA y no puede dejar de serlo, nadie le puede retirar este privilegio ni siquiera él mismo. El administrador de la base de datos puede conceder este permiso a otros usuarios que se convierten en usuarios DBA pero con menor prioridad. 2.b.- RESOURCE: es el nivel inmediato inferior al DBA, permite la creación de tablas, índices, etc y la concesión de permisos a otros usuarios sobre lo creado o sobre aquellas tablas no creadas por él, pero sobre las que se le hayan concedido permisos. 2.c.- CONNECT: es el nivel más bajo y sólo permite acceso a instrucciones de consulta o actualización de tablas. PERMISOS SOBRE BASES DE DATOS Cuando se crea una base de datos, el único usuario que por defecto tiene acceso a ella es el que la crea, usuario DBA propietario. Este usuario administrador será quien conceda o revoque permisos sobre esa base de datos y sus tablas, estas operaciones se realizan con las siguientes instrucciones: GRANT {DBA | RESOURCE | CONNECT} TO {PUBLIC | lista_usuarios} REVOKE {DBA | RESOURCE | CONNECT} FROM {PUBLIC | lista_usuarios} PERMISOS SOBRE TABLAS Y COLUMNAS Cuando se crea una tabla mediante CREATE TABLE, esta instrucción se encarga de conceder todos los permisos sobre la tabla a todos los usuario PUBLIC. Los permisos que se pueden asignar a las tablas son los siguientes: Select [(lista_columnas)]: lectura de la tabla, si se indica una lista de columnas ese permiso de lectura se aplicará solo a las columnas indicadas. Update [(lista_columnas)]: de actualización de la tabla, si se indican columnas, el permiso será solo para modificar las columnas indicadas. Insert: inserción de filas en la tabla. Delete: borrado de filas en la tabla. Index: creación de índices para dicha tabla. Alter: alteración de la estructura de la tabla, es el único permiso que no se asigna por defecto en la creación de la tabla mediante CREATE TABLE. All [privileges]: engloba todos los permisos anteriores Para cambiar los permisos generados por CREATE TABLE se utilizan las instrucciones GRANT y REVOKE con los siguientes formatos: GRANT permisos ON tabla TO {PUBLIC | lista_usuarios} [WITH GRANT OPTION] REVOKE permisos ON tabla FROM {PUBLIC | lista_usuarios} BLOQUEOS En aplicaciones de bases de datos instaladas en entornos multiusuario surge el problema de la concurrencia, es decir la simultaneidad de acceso de distintos usuarios a los mismos datos para realizar operaciones de consulta y/o actualización que podrían llevar a inconsistencias en la lectura de los valores o pérdida de información. Para evitar posibles inconsistencias el CTSQL dispone de un mecanismo denominado “bloqueo”, que básicamente consiste en la limitación del acceso a determinados datos por parte del primer programa que los solicita, deforma que los demás programas no puedan leerlos ni modificarlos. Existen distintos niveles de bloqueos dependiendo de los objetos de la base de datos que se manejan: BLOQUEO DE LA BASE DE DATOS Consiste en la apertura de la base de datos por un solo usuario, es una operación que solamente pueden realizar los usuarios que tienen permiso DBA sobre la base de datos. La instrucción que se utiliza para bloquear la base de datos es: DATABASE base_datos EXCLUSIVE En caso de realizar esta operación cuando la base de datos ya está seleccionada por otro usuario, se produce un error, que también ocurrirá cuando una vez seleccionada la base de datos en modo exclusivo, otro usuario con permisos sobre dicha base de datos intente acceder a ella. Para desbloquear la base de datos basta cerrarla con la instrucción CLOSE DATABASE. BLOQUEO DE TABLAS Para bloquear una tabla de una base de datos hay que ejecutar la instrucción: LOCK TABLE tabla IN {SHARE | EXCLUSIVE} MODE Hay dos modos diferentes de bloquear las tablas: IN SHARE MODE: indica que otros usuarios pueden leer la tabla bloqueada pero no pueden actualizarla. IN EXCLUSIVE MODE: otros usuarios no pueden leer ni modificar la tabla bloqueada, es la forma más conveniente de bloqueo cuando se van a realizar cambios sobre un gran número de filas de la tabla. La forma de desbloquear una tabla, sea cual sea el bloqueo que se había aplicado es mediante la ejecución de la instrucción: UNLOCK TABLE tabla Solamente puede desbloquear una tabla el usuario que la bloqueó, por tanto hay que tener mucho cuidado con el bloqueo de tablas. Si se realiza esta instrucción sobre una tabla que no está bloqueada no se produce ningún error. BLOQUEO DE FILAS No existe una instrucción específica para bloquear filas de una tabla, sin embargo cuando se intenta modificar una fila mediante la instrucción UPDATE, se produce un bloqueo automático de dicha fila, si la instrucción UPDATE se encuentra que la fila está bloqueada por otra instrucción UPDATE, se quedará en espera hasta que se termine de ejecutar la instrucción que tiene bloqueada la fila. Cuando interesa bloquear un número indeterminado de filas de una tabla, hay que trabajar sobre una base de datos transaccional, ya que las filas de una tabla se bloquean cuando intervienen en una transacción. 3.26.- TRANSACCIONES Se llama transacción o unidad lógica de trabajo a un conjunto de instrucciones de recuperación o actualización sobre la base de datos que o bién se ejecutan todas o no se ejecuta ninguna. Las transacciones tienen una misión importante en el trabajo con bases de datos y es preservar a la base de datos de incoherencias que pudieran producirse por caída del sistema o terminación anormal del programa por cualquier otra razón. Ejemplo: si queremos modificar el presupuesto del departamento de Personal en 1.000.000 de pts., pero no queremos que se modifique el presupuesto total de la empresa, por tanto vamos a disminuir en la misma cantidad el presupuesto del departamento Dirección Comercial. Tendremos que ejecutar las siguientes operaciones: DATABASE EMPRESA; UPDATE TDEPTO SET PRESU=PRESU+1 WHERE NOMDE=’PERSONAL’; UPDATE TDEPTO SET PRESU = PRESU –1 WHERE NOMDE=’DIRECCION COMERCIAL’; Las dos instrucciones deben ejecutarse o no ejecutarse ninguna ya que si se ejecuta la primera y no la segunda nuestra base de datos contendría una información errónea. BASES DE DATOS TRANSACCIONALES Para poder trabajar con transacciones hay que hacerlo sobre una base de datos transaccional que se puede tener si en la creación utilizamos la instrucción: CREATE DATABASE bas_datos WITH LOG IN “fichero_log” “fichero_log”: nombre de fichero con su path completo que se va a utilizar para recoger las transacciones. Si ya existe la base de datos y no era transaccional, podemos convertirla en transaccional mediante la instrucción: START DATABASE base_datos WITH LOG IN “fichero_log” Esta instrucción se utiliza para convertir una base de datos en transaccional o para cambiar el fichero log de una base de datos que ya es transaccional, el motivo de este cambio es que este fichero aumenta de tamaño con cada transacción que queda anotada y por tanto es conveniente sustituirlo por uno nuevo a la vez que el antiguo queda como copia de seguridad. Siempre debe existir el fichero log asociado a una base de datos transaccional si lo perdemos la base de datos no podrá abrirse. En la tabla systables del catálogo de la base de datos, cuando se crea una base de datos transaccional, aparece una línea que describe el fichero log asociado. La operación de convertir una base de datos en transaccional solamente la pueden realizar el propietario de la base de datos o usuarios con permiso DBA sobre dicha base de datos, y la operación se debe realizar con la base de datos cerrada. Si queremos realizar la operación contraria, convertir una base de datos transaccional en no transaccional, podemos utilizar la instrucción: START DATABASE base_datos WITH LOG IN “”” TRANSACCIONES Cual es el grupo de instrucciones que forman una transacción depende de la lógica del problema y será el programador el encargado de agruparlas, pero siempre es necesario indicar a la base de datos donde empieza y donde termina una transacción, para ello existen las siguientes instrucciones: BEGIN WORK indica el comienzo de una transacción. COMMIT WORK finaliza la transacción ejecutando los cambios solicitados. ROLLBACK WORK finaliza la transacción sin realizar los cambios que se habían solicitado. Las transacciones que finalizan con ROLLBACK WORK, no se anotan en el fichero log, ya que no producen modificaciones sobre nuestra base de datos, pero si se anotan todas aquellas que finalizan con COMMIT WORK. Si ha ocurrido un fallo y tenemos que recuperar la base de datos, se realiza mediante la instrucción: ROLLFORWARD DATABASE base_datos [TO fichero_resultado]