Artículos técnicos Grupo Danysoft: Introducción al SQL de InterBase: DDL y DML Segunda Parte Tercer Artículo Por Pablo Reyes Equipo Grupo Danysoft julio de 2002 - (902) 123146 www.danysoft.com Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 1/8
Introducción al SQL de InterBase: DDL y DML (segunda parte) Este artículo es el tercero de una serie dedicados al uso de InterBase con Delphi. Debido a su extensión, el tema de este artículo fue dividido en dos. Esta es la segunda parte. Objetivo El objetivo de este artículo es explorar las sentencias SQL del tipo DML (Data Manipulation Language) para insertar, actualizar, eliminar y obtener conjuntos de datos de una base de datos InterBase. También veremos el uso de disparadores, tema que quedó pendiente del artículo anterior. En este artículo utilizaré una base de datos de InterBase resultante de migrar las tablas del alias DBDemos. Algunas de las tablas las hemos migrado en artículos anteriores. Confío en que podéis hacerlo sin mi ayuda. Insertando datos Siguiendo el orden planteado en el artículo anterior vamos a dar el primer paso luego de la creación de la base de datos: insertar datos en ella. La cláusula insert permite insertar datos en una tabla. Vamos a insertar un país en la tabla country. Les recuerdo la sentencia SQL con la que creamos esta tabla. create table country (name varchar(24) not null primary key, capital varchar(24) not null, continent varchar(24) not null, area integer not null, population integer not null) Código Fuente 1 - Tabla country Para que nuestra sentencia SQL insert no sea rechazada debemos prestar atención a las restricciones impuestas a la tabla. En primer lugar, ningún campo acepta el valor nulo con lo cual debemos proveer un valor para cada uno de ellos. En segundo lugar, el campo name es clave primaria lo que significa que no acepta valores duplicados. La siguiente sentencia inserta el país Argentina en la tabla country: insert into country (name, capital, continent, area, population) values ("Argentina", "Buenos Aires", "America", 3760000, 35000000) Código Fuente 2 - Inserción de Argentina Si ejecutáramos dos veces seguidas esta misma sentencia la segunda vez sería rechazada pues estaríamos violando la imposición del campo name que por ser clave primaria no acepta valores duplicados. Es importante que desde el principio nos acostumbremos a considerar en todo momento las imposiciones de una tabla ya que son las responsables de mantener la integridad de los datos y nunca dan tregua. Si una sentencia viola una imposición entonces será rechazada con el correspondiente mensaje de error. Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 2/8
Imagen de Pantalla 1 - Error por clave duplicada La sintaxis de la cláusula insert es bastante simple. Debemos indicar el nombre de la tabla, la lista de campos y la lista de valores. Ambas listas deben tener la misma cantidad de elementos y al primer campo se le asignará el primer valor, al segundo campo el segundo valor y así sucesivamente. Transacciones Un concepto que hasta ahora no mencioné es el de transacción. Una transacción es un conjunto de acciones que deben ser ejecutadas exitosamente para que los cambios realizados por ellas sean aceptados como permanentes. Si una de las acciones falla entonces los cambios realizados por las acciones ejecutadas son deshechos. Las transacciones son fundamentales para mantener la integridad de los datos de una base de datos. InterBase soporta el uso de transacciones implícitas y explícitas. Cuando no se especifica explícitamente el uso de transacciones, InterBase utiliza transacciones implícitas a nivel de registro. Avanzaré más sobre este tema cuando veamos el desarrollo de aplicaciones Delphi con InterBase en futuros artículos. Interactive SQL inicia transacciones implícitamente pero no las finaliza. Es decir, cuando ejecutamos una sentencia SQL como la utilizada para insertar el país Argentina en la tabla country, Interactive SQL inicia una transacción implícitamente pero no la finaliza. Si intentamos cerrar Interactive SQL inmediatamente luego de ejecutar dichaa sentencia una ventana de diálogo nos avisará que hay una transacción activa. Imagen de Pantalla 2 - Transacciones activas Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 3/8
Podemos finalizar la transacción activa explícitamente de dos formas: 1. Ejecutando la cláusula commit, con lo cual los cambios realizados en el contexto de la transacción serán aceptados como permanentes. Desde el menú de Interactive SQL, Transactions Commit. 2. Ejecutando la cláusula rollback, con lo cual los cambios realizados en el contexto de la transacción serán deshechos. Desde el menú de Interactive SQL, Transactions Rollback. Interactive SQL no permite iniciar transacciones explícitamente. Modificando datos Vamos a modificar el registro insertado en el punto anterior. Actualmente la población de Argentina es de 37 millones de habitantes. La siguiente sentencia SQL modifica el valor del campo population de la tabla country y le asigna el valor 37.000.000 para el país Argentina. update country set population = 37000000 where name = "Argentina" Código Fuente 3 - Modificación de los datos de la tabla country La cláusula update puede afectar a ninguno, uno o más registros dependiendo de la cláusula where. En este caso el campo referenciado en la cláusula where es clave primaria lo que nos garantiza que la cantidad de registros afectados serán ninguno o uno. Si no hubiéramos incluido la cláusula where la sentencia anterior hubiera afectado a todos los registros de la tabla country. Para la cláusula update debemos indicar el nombre de la tabla, una lista de nombres de campos con su respectivos valores y, opcionalmente, aunque casi siempre necesario, una condición lógica para determinar los registros que deben ser modificados. Borrando datos Para borrar datos sólo es necesario indicar el nombre de la tabla y una condición lógica para determinar los registros que deben ser borrados. La siguiente sentencia SQL borra el país Argentina de la tabla country. delete from country where name = "Argentina" Código Fuente 4 - Borrado de datos de la tabla country La cláusula delete también puede afectar ninguno, uno o más registros. Todo depende de la cláusula where indicada. Disparadores (triggers) Los disparadores quedaron pendientes del capítulo anterior, aunque algunas cosas he dicho acerca de ellos en el primer artículo de esta serie. Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 4/8
El siguiente código crea un disparador para la tabla customer que se dispara antes de insertar un registro. create trigger custno for customer before insert as declare variable icust integer; begin select newcust from nextcust into :icust; icust = icust + 1; update nextcust set newcust = :icust; new.custno = icust; end; El código anterior crea un disparador que hace lo siguiente: declara la variable icust de tipo integer. selecciona el único campo del único registro de la tabla nextcust y almacena el valor en la variable icust. le suma 1 a la variable icust. actualiza la tabla nextcust con el nuevo valor. le asigna al campo custno del nuevo registro de la tabla customer el valor de la variable icust. De esta manera, cada vez que insertamos un registro en la tabla customer el valor del campo custno es generado automáticamente, algo así como un campo auto-incrementado. Como habrán observado, la sintaxis del lenguaje utilizado en los disparadores es similar al lenguaje SQL, salvo algunos agregados pero que son fáciles de comprender por cualquier programador. La documentación de InterBase es muy completa y fácil de seguir. Allí encontrarán una descripción del lenguaje utilizado para escribir procedimientos almacenados y disparadores. Obteniendo conjuntos de datos La cláusula select permite obtener un conjunto de datos de una o más tablas. Es la sentencia más amplia y compleja del grupo DML. Vamos a conocerla de a poco. Antes de comenzar necesitamos datos en nuestra base de datos. Para no hacer más extenso de lo necesario el presente artículo, asumiré que nuestra base de datos de InterBase tiene los mismos datos que las tablas del alias DBDemos. La forma más simple de la cláusula select es la siguiente: select * from country Código Fuente 5 - Obteniendo todos los registros con todos los campos de la tabla country La sentencia anterior devuelve un conjunto de datos compuesto por todos los registros de la tabla country con todos sus campos. El asterisco (*) indica que todos los campos de la tabla deben ser incluidos en el conjunto devuelto. Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 5/8
En tablas con muchos campos normalmente es conveniente obtener sólo algunos de ellos para minimizar el tamaño total del conjunto obtenido. En este caso en lugar del asterisco (*), debemos indicar los nombres de los campos que queremos obtener. select name, capital from country Código Fuente 6 - Obteniendo todos los registros con algunos campos de la tabla country La sentencia SQL anterior devuelve todos los registros de la tabla country incluyendo solamente los campos name y capital. Si queremos limitar la cantidad de registros obtenidos debemos indicar una condición lógica por medio de la cláusula where. Todos los registros que cumplan con la condición indicada serán incluidos en el conjunto de datos retornado. La siguiente sentencia SQL devuelve todos los registros de la tabla country cuya población sea mayor a 20 millones de habitantes. select * from country where population > 20000000 Código Fuente 7 - Obteniendo algunos registros de la tabla country Si queremos obtener el conjunto de datos ordenado de determinada forma debemos indicar el orden deseado por medio de la cláusula order by. La siguiente sentencia SQL devuelve todos los registros de la tabla country ordenados por el campo area. select * from country order by area Código Fuente 8 - Obteniendo datos ordenados de la tabla country Obteniendo datos de varias tablas Es posible obtener un conjunto de datos compuestos por datos de más de una tabla. En este caso la sentencia SQL es un poco más compleja. Hay dos formas de combinar los datos de varias tablas. La siguiente sentencia SQL muestra una de ellas. select orders.orderno, customer.company, orders.saledate, orders.itemstotal from orders, customer where orders.custno = customer.custno and orders.itemstotal >= 500 order by company Código Fuente 9 - Obteniendo datos de varias tablas La sentencia SQL anterior devuelve un conjunto de datos como resultado de combinar registros de las tablas orders y customer para los cuales el valor del campo itemstotal de la Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 6/8
primera tabla sea mayor o igual a 500, ordenados por el campo company de la segunda tabla. Los campos obtenidos son orderno, company, saledate e itemstotal. Para cada campo debemos indicar a que tabla pertenece anteponiendo al nombre del campo el nombre de la tabla de acuerdo a los nombres de tablas indicados en la cláusula from. La condición lógica de la cláusula where indica de qué manera deben ser empalmados los registros de ambas tablas. En este caso, los empalma cuando el campo custno de ambas tablas tiene el mismo valor. Otra forma de escribir esta sentencia es la siguiente: select orders.orderno, customer.company, orders.saledate, orders.itemstotal from orders inner join customer on orders.custno = customer.custno where orders.itemstotal >= 500 order by company Código Fuente 10 - Obteniendo datos de varias tabla (INNER JOIN) El conjunto de datos obtenidos con esta versión es exactamente igual al anterior. La diferencia está en la sintaxis. Personalmente prefiero la segunda versión porque es más fácil de entender ya que las condiciones de empalme están separadas de las condiciones de selección de registros. Otra manera de obtener datos de varias tablas es uniendo el resultado de una o más sentencias para obtener un único conjunto de datos. select addr1, addr2, state from customer union select address1, address2, state from vendors Código fuente 11 Obteniendo datos de varias tablas (UNION) La sentencia SQL anterior devuelve un conjunto de datos resultante de unir el conjunto de datos obtenido por cada una de las sentencias select involucradas. La única imposición de la cláusula union es que los conjuntos de datos obtenidos por las sentencias select involucradas deben ser compatibles, es decir, deben tener la misma estructura. Para cumplir con esta imposición se suelen crear campos fantasmas para hacer que los conjuntos de datos obtenidos sean compatibles entre sí. Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 7/8
Indices Los índices permiten acceder a los datos de una tabla en forma ordenada. Dicho orden es definido al momento de crear el índice. Algunos índices son creados automáticamente por InterBase cuando, por ejemplo, creamos una clave primaria o una clave foránea. Los índices están íntimamente relacionados con una palabra fundamental en el mundo de las RDBMS: rendimiento. El rendimiento es uno de los factores más importantes de un RDBMS. Como desarrolladores de aplicaciones de bases de datos es una lección que aprendemos rápidamente. Si nuestra aplicación tarda cinco minutos en mostrar un registro seguramente no generará sensaciones de satisfacción en nuestros usuarios. En muchas ocasiones nos veremos enfrentados a la necesidad de crear índices para mejorar el rendimiento de nuestra aplicación. El caso más típico es con consultas frecuentes en las que se accede a tablas con muchos registros y en un orden diferente al de la clave primaria o foráneas que puedan existir. create index cia on customer company La sentencia anterior crea el índice cia para la tabla customer compuesto por el campo company. Por defecto, el orden del índice es ascendente. Además, un índice puede ser compuesto, es decir, estar compuesto por más de un campo. Si bien el uso de índices puede mejorar el rendimiento general de una aplicación, su abuso puede deteriorarlo. Cada vez que insertamos un registro en una tabla con índices, estos índices deben ser actualizados, con la consecuente penalidad en rendimiento. Como en muchas cosas de la vida, debemos aprender a encontrar el equilibrio. Resumen Hemos visto como manipular los datos de una base de datos, insertando, actualizando y eliminando registros de una tabla. Este tipo de operaciones siempre afecta a una única tabla ya que no es posible con una única sentencia, por ejemplo una sentencia insert, insertar registros en más de una tabla. Como lo prometido es deuda, hemos visto como crear un disparador. También hemos visto como obtener conjuntos de datos mediante la sentencia select. En este caso sí podemos operar sobre más de una tabla con una única sentencia. Aquí los índices juegan un papel fundamental a la hora de hablar de rendimiento, esa palabrita que en materia de aplicaciones de bases de datos debemos honrar siempre. En el próximo artículo de esta serie nos meteremos de lleno en el desarrollo de aplicaciones Delphi con InterBase Veremos los componentes de acceso a datos disponibles y aprenderemos algunos truquitos que no están en la documentación oficial. Felices VACACIONES! Introducción al SQL de InterBase: DDL y DML (segunda parte) Grupo Danysoft - 8/8