TRABAJANDO CON SQL*PLUS El objetivo de este tema es simplemente, hacer una revisión de los conceptos avanzados de SQL, para ello, empezaremos por ver como se accede a SQL*PLUS y como crear usuarios, para posteriormente, crear las tablas con las que vamos a trabajar y luego mostrar dichos conceptos avanzados de SQL como son las vistas, índices, clusters, disparadores, … Acceso a SQL*PLUS Dentro del grupo de programas del menú inicio Oracle – OraHome90 podemos encontrar Application Development y dentro de él un enlace a SQL*PLUS. Si no se cambió la clave durante la instalación, para acceder al sistema podremos usar el superusuario sys cuya clave es change_on_install. Si queremos modificar la contraseña de sys, una vez que accedamos al sistema como sys, escribiremos la sentencia: ALTER USER sys IDENTIFIED BY <nuevo password> A continuación debemos crear una cuenta de usuario para que tengamos un acceso restringido a las propiedades del sistema. Esto lo podemos hacer conectados como sys con las siguientes sentencias: CREATE USER <login> IDENTIFIED BY <password> DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP QUOTA 4M ON USERS QUOTA 1M ON TEMP; GRANT CONNECT, RESOURCE TO <login> Como podemos imaginar, para eliminar un usuario tenemos que escribir. DROP USER <login> Creación de las tablas e inserción de datos Vamos a utilizar el ejemplo de proveedor-pieza-proyecto-ventas para el usuario que hemos creado anteriormente, las tablas correspondientes son: create table proveedor( codpro varchar2(3) not null primary key, nompro varchar2(30) not null, status number check(status>=1 and status<=10), ciudad varchar2(15) ); create table pieza( codpie varchar2(3) not null primary key, nompie varchar2(10) not null, color varchar2(10), peso number(5,2) check(peso>0 and peso<=100), ciudad varchar2(15) ); 1 create table proyecto( codpj varchar2(3) not null primary key, nompj varchar2(20) not null, ciudad varchar2(15) ); create table ventas( codpro references proveedor(codpro), codpie references pieza(codpie), codpj references proyecto(codpj), cantidad number(4), primary key(codpro, codpie, codpj) ); Si la descripción anterior se encuentra en un archivo de nombre tablas.sql, podremos cargarlo escribiendo: @tablas o bien start tablas Tras ejecutar la sentencia anterior, si no hay errores sintácticos, el sistema nos dirá que la tabla se ha creado correctamente. Si queremos eliminar alguna tabla, escribiremos: DROP TABLE <nombre de la tabla> Para ver la estructura de la tabla creada podemos usar: DESCRIBE <nombre de la tabla> Si una vez creadas las tablas nos encontramos con el problema de que tenemos que insertar algún cambio sobre alguna de ellas tendremos que usar la sentencia alter, por ejemplo, vamos a añadir el campo fecha a la tabla ventas: alter table ventas add(fecha date default sysdate); Para insertar datos usamos la sentencia insert: insert insert insert insert into into into into proveedor values('S1','Jose Fernandez',2,'Madrid'); pieza values('P1','Tuerca','Gris',2.5,'Madrid'); proyecto values('J1','Proyecto1','Londres'); ventas values('S1','P1','J2',100,TO DATE('25/12/2000')); Veamos cuáles son los datos insertados en las tablas: SQL> select * from proveedor; COD --S1 S2 S3 S4 S5 NOMPRO STATUS CIUDAD ------------------------------ ---------- -------Jose Fernandez 2 Madrid Manuel Vidal 1 Londres Luisa Gomez 3 Lisboa Pedro Sanchez 4 Paris Maria Reyes 5 Roma 2 SQL> select * from pieza; COD --P1 P2 P3 P4 P5 NOMPIE ---------Tuerca Tornillo Arandela Clavo Alcayata COLOR PESO CIUDAD ---------- ---------- -------Gris 2,5 Madrid Rojo 1,25 Paris Blanco 3 Londres Gris 5,5 Lisboa Blanco 10 Roma SQL> select * from proyecto; COD --J1 J2 J3 J4 NOMPJ -------------------Proyecto1 Proyecto2 Proyecto3 Proyecto4 CIUDAD --------------Londres Londres Paris Roma SQL> select * from ventas; COD --S1 S1 S1 S2 S4 S1 S5 S1 S1 S2 S2 S3 S3 S3 S4 S4 S4 S1 S1 S1 COD --P1 P1 P2 P2 P2 P3 P3 P4 P4 P5 P2 P1 P2 P5 P5 P3 P1 P1 P4 P2 COD CANTIDAD FECHA --- ---------- -------J2 100 25/12/00 J3 500 30/01/00 J1 200 02/02/00 J2 15 25/05/00 J3 1700 14/12/00 J1 800 12/01/00 J2 30 10/12/00 J1 10 25/11/00 J3 250 12/05/00 J2 300 10/08/00 J1 4500 25/07/00 J1 90 01/07/00 J1 190 30/05/00 J3 20 26/06/00 J1 15 14/04/00 J1 100 22/09/00 J3 1500 21/08/00 J1 150 28/02/00 J4 290 02/01/00 J4 175 13/12/00 20 filas seleccionadas. Consultas de ejemplo 1. Encontrar las ventas cuya cantidad esté entre 200 y 1000 inclusive, que pertenezcan al proveedor de nombre Jose Fernandez y mostrar los resultados ordenados por fecha: select V.codpro, codpie, codpj, cantidad, fecha from ventas V, proveedor P where V.codpro=P.codpro and P.nompro LIKE 'Jose Fernandez' and cantidad between 200 and 1000 order by fecha; 3 3. Encontrar los proveedores que hayan hecho al menos dos pedidos: select codpro from ventas group by codpro having count(codpro)>=2; 4. Encontrar la cantidad total de cada pieza enviada a cada proyecto ordenado descendentemente por dicho total: select codpie, codpj, sum(cantidad) from ventas group by codpie, codpj order by sum(cantidad) DESC; Gestión de vistas Una vista es una tabla lógica cuya información se deriva de una tabla, de un conjunto de tablas o bien de otras vistas de la base de datos. Si el contenido de las tablas cambia, este cambio se ve reflejado en las vistas. A diferencia de una tabla, una vista no contiene ningún dato: únicamente contiene una consulta SQL. Los datos que se recuperan de esa consulta se presentan en forma de tabla. En realidad, si nosotros no hemos creado esa vista, podemos pensar que estamos trabajando directamente con la tabla. Al igual que una tabla, se pueden insertar, actualizar, borrar y seleccionar los datos de una vista. ¿Por qué usar vistas?: • Las vistas pueden proporcionar un nivel adicional de seguridad. Por ejemplo, podemos tener una tabla de empleados de nuestra empresa y podemos querer usar una vista para que los jefes de departamento sólo puedan visualizar la información de sus subordinados. • Las vistas permiten ocultar la complejidad de los datos. Una base de datos Oracle está formada por muchas tablas. Se puede recuperar la información de dos o más tablas haciendo una combinación, pero esta combinación puede llevar a gran confusión a un usuario final. Muchas veces tendremos que crear vistas que son combinaciones de varias tablas, de modo que el usuario final lo verá como una sola tabla. Para crear una vista en Oracle se utiliza la sentencia create_view. Como ejemplo vamos a crear una vista que representa el conjunto de piezas de Londres: create view PiezasLondres as select codpie,nompie,color,peso from pieza where pieza.ciudad like 'Londres'; En la cláusula as se especifica la consulta que determina qué filas y columnas de la tabla o tablas almacenadas forman parte de la vista. A partir de ahora PiezasLondres podrá ser tratada como una tabla sin serlo en realidad. Por ejemplo, podemos hacer una consulta del estilo: SQL> select * from PiezasLondres; COD NOMPIE COLOR PESO --- ---------- ---------- ---------P3 Arandela Blanco 3 Pero, ¿cómo modificamos una vista? Se pueden utilizar los comandos delete, insert y update sólo en determinadas ocasiones. La razón de esto es que, puesto que la tabla no existe como una entidad física (relación almacenada), para el caso de insertar una nueva tupla, la cuestión es dónde se colocaría un campo nulo. Por ejemplo, en nuestro ejemplo si hacemos una inserción del tipo: 4 SQL> insert into PiezasLondres values('P9','Rodamiento', 'Rojo', 90); 1 fila creada. SQL> select * from PiezasLondres; COD NOMPIE COLOR PESO --- ---------- ---------- ---------P3 Arandela Blanco 3 SQL> select * from pieza; COD --P1 P2 P3 P4 P5 P9 NOMPIE ---------Tuerca Tornillo Arandela Clavo Alcayata Rodamiento COLOR PESO CIUDAD ---------- ---------- --------------Gris 2,5 Madrid Rojo 1,25 Paris Blanco 3 Londres Gris 5,5 Lisboa Blanco 10 Roma Rojo 90 6 filas seleccionadas. vamos a tener un problema a la hora de rellenar el campo ciudad de la tabla pieza, ya que por ningún lado lo hemos definido, con lo que se insertaría null y si volvemos a hacer un select sobre la vista, no se nos mostrará esta inserción. Lo que tenemos que hacer para solucionarlo es modificar la vista para insertarle el campo ciudad en la consulta: SQL> delete from pieza where codpie='P9'; 1 fila suprimida. SQL> drop view PiezasLondres; Vista borrada. SQL> create view PiezasLondres as 2 select codpie,nompie,color,peso,ciudad from pieza 3 where pieza.ciudad like 'Londres'; Vista creada. SQL> select * from PiezasLondres; COD NOMPIE COLOR PESO CIUDAD --- ---------- ---------- ---------- --------------P3 Arandela Blanco 3 Londres SQL> insert into PiezasLondres values 2 ('P9','Rodamiento','Rojo',90,'Londres'); 1 fila creada. SQL> select * from PiezasLondres; COD --P3 P9 NOMPIE ---------Arandela Rodamiento COLOR PESO CIUDAD ---------- ---------- --------------Blanco 3 Londres Rojo 90 Londres 5 SQL> select * from pieza; COD --P1 P2 P3 P4 P5 P9 NOMPIE ---------Tuerca Tornillo Arandela Clavo Alcayata Rodamiento COLOR PESO CIUDAD ---------- ---------- --------------Gris 2,5 Madrid Rojo 1,25 Paris Blanco 3 Londres Gris 5,5 Lisboa Blanco 10 Roma Rojo 90 Londres 6 filas seleccionadas. Índices Del mismo modo que el índice de un libro ayuda a buscar rápidamente la información, un índice asociado a una tabla ayuda a recuperar los datos más rápidamente. Si una aplicación se ejecuta lentamente, un índice adecuadamente situado hará que se ejecute con mayor velocidad. La ausencia o presencia de un índice asociado a una tabla no influye sobre la sintaxis de las sentencias SQL para trabajar con la tabla, un índice en Oracle no es más que un mecanismo para acelerar la velocidad de acceso a la información de una tabla (pensad en las aplicaciones bancarias si no usasen índices para las tablas de clientes lo que ocurriría). Aunque los índices agilizan la recuperación de los datos (data retrieval) de los datos de las tablas, sin embargo, ralentizan las actualizaciones y ocupan espacio en disco, ya que, cuando se realizan actualizaciones de una tabla de la base de datos, cada uno de los índices basados en esa tabla necesita también una actualización. Vemos, por tanto, que un índice es un arma de doble filo, así que se debe realizar un análisis de para que va a ser utilizada cada tabla antes de asociarle un índice. NO SE DEBEN CREAR ÍNDICES SOBRE LAS CLAVES PRIMARIAS, ya que cada tabla posee un índice asociado a la clave primaria y lo único que conseguiríamos es ralentizar el proceso al tener más de un índice para una clave. Cuando se crea un índice lo único que tenemos que hacer es pensar que es Oracle el que se encarga de mantenerlo, nosotros sólo hemos de definirlo. Para crear un índice utilizamos la sentencia create index, cuya sintaxis es: CREATE INDEX nombre_del_indice ON tabla(campo [ASC | DESC], ...) Por ejemplo, si queremos acelerar las consultas cuando busquemos a un proveedor por su nombre, podemos crear un índice asociado al campo nompro de la tabla proveedor. create index indice_proveedores on proveedor(nompro); Cuando se crea una tabla es más eficiente insertar los registros y después crear el registro, porque si se hace al revés, cada vez que se inserte un registro, se deberá actualizar el índice. Tenemos la posibilidad de crear también índices compuestos, es decir, un índice que se crea sobre más de un campo de la tabla. Por ejemplo, supongamos que sobre la tabla proveedor consultamos habitualmente los campos nompro, status y ciudad. Podríamos entonces crear un índice como el siguiente, para que cada vez que accedamos al campo nompro, a los campos nompro y status o a los campos nompro, status y ciudad haya un incremento de velocidad. create index index_proveedor on proveedor(nompro,status,ciudad); 6 Si embargo, no se producirá una mejora si la consulta se refiere a status o a ciudad individualmente o a nompro y ciudad, o a status y ciudad. Esto es, siempre se debe consultar de izquierda a derecha sin dejar ninguno de la izquierda sin referenciar. Para eliminar un índice podemos tener varias razones: • El índice no se necesita más, • Por las características de la tabla, el índice no mejora la eficiencia, • Necesitamos cambar los campos que se indexan, • Necesitamos rehacer un índice muy fragmentado. La sentencia para eliminarlo es: DROP INDEX nombre del indice Se debe tener en cuenta que cuando se borra una tabla, también se borran los índices asociados a dicha tabla. Clusters Un cluster proporciona un método alternativo de almacenar información en las tablas. Un cluster lo forman un conjunto de tablas que se almacenan en los mismos bloques de datos porque comparten campos comunes (llave del cluster) y que son frecuentemente accedidas de forma conjunta. Por ejemplo, las tablas proveedor y ventas comparten el campo codpro. Si se incluyen las dos tablas en el mismo cluster, Oracle físicamente almacena todas las filas de cada codpro de ambas tablas en los mismos bloques de datos. Como los clusters almacenan registros relacionados en los mismos bloques, los beneficios son: se reduce el acceso a disco y se mejora el rendimiento; y la llave del cluster (columnas comunes entre las tablas del cluster) almacena cada valor una sola vez de modo independiente al número de registros de las tablas que contengan dicho valor. Después de crear un cluster se pueden crear las tablas que pertenecen al cluster. No obstante, antes de que se puedan insertar registros en las tablas del cluster es necesario indexar el cluster. Dos restricciones sobre los clusters, se deben usar para tablas que se van a consultar mucho y se van a modificar poco, si no se cumple esto, el cluster resultante tendrá un efecto negativo sobre el rendimiento porque no aprovechamos las ventajas que nos ofrece. Ejemplo: SQL> drop table ventas; Tabla borrada. SQL> drop table proveedor; Tabla borrada. SQL> create cluster cluster_codpro(codpro varchar2(3)); Agrupamiento creado. SQL> create table proveedor( 2 codpro varchar2(3) not null primary key, 3 nompro varchar2(30) not null, 4 status number check(status>=1 and status<=10), 5 ciudad varchar2(15)) 6 cluster cluster_codpro(codpro); Tabla creada. 7 SQL> create table ventas( 2 codpro varchar2(3) references proveedor(codpro), 3 codpie varchar2(3) references pieza(codpie), 4 codpj varchar2(3) references proyecto(codpj), 5 cantidad number(4), 6 primary key(codpro, codpie, codpj)) 7 cluster cluster_codpro(codpro); Tabla creada. SQL> create index indice_cluster on cluster cluster_codpro; Índice creado. Para eliminar un cluster tenemos que usar drop cluster. Cuando se borra un cluster, se borra también el índice asociado a él. La sintaxis es: DROP CLUSTER nombre_del_cluster [INCLUDING TABLES [CASCADE CONSTRAINTS]]; Si un cluster contiene tablas no podrá ser eliminado a menos que se eliminen antes las tablas o que se incluyan en la sentencia de eliminanción INCLUDING TABLES. El cluster no podrá ser eliminador si las tablas contienen campos que son referencados por llaves externas. Solucionable con CASCADE CONSTRAINTS. Podemos eliminar las tablas del cluster sin afectar al cluster. También podemos eliminar el índice, pero no podremos acceder a la información contenida en las tablas del cluster hasta que se reconstruya el índice. 8