BASES DE DATOS EN VISUAL BASIC ACCESS + SQL by Damián Sottosanti Ultima actualización: 03-08-2004 CREAMOS LA BASE DE DATOS EN ACCESS Abrimos Access y elegimos "Crear una nueva base de datos usando" "Base de datos de Access en blanco" Lo guardamos, por ejemplo, en "mis documentos", con el nombre "db1.mdb" Después creamos una tabla en vista diseño Ingresen los mismos datos q ven a continuación, ya q estos son los datos (la tabla) q vamos a usar para programar. Guarden la tabla con el nombre "Tabla1" Ahora ingresamos datos en la tabla: Y ahora lo mas importante. Para no tener inconvenientes de compatibilidad vamos a hacer lo siguiente: "Herramientas -> Utilidades de las base de datos -> Convertir base de datos -> A una versión anterior de la base de datos de Access..." Guardamos con el nombre "base1.mdb" Esta base de datos llamada "base1.mdb" es la q vamos a usar en Visual Basic. No usaremos la otra (db1) por motivos de compatibilidad. En definitiva, ambas bases de datos son iguales, solo cambia la versión. AHORA TRABAJAMOS EN VISUAL BASIC Cuando creamos el proyecto lo primero q debemos hacer para trabajar con nuestra base de datos es la "referencia al motor de bases de datos de Microsoft". Para esto desde Visual Basic vamos al menu Proyecto -> Referencia y seleccionamos Microsoft DAO 3.51 Object Library (si tenes otra versión igual tiene q funcionar). Ahora para ver lo q estamos haciendo cuando ejecutamos, vamos a agregar una ListBox (llamada List1) en nuestro formulario. A partir de ahora es todo codigo. Creamos las variables en la parte General del formulario: Dim BDD as DataBase 'Objeto para manejar la base de datos Dim TBL as RecordSet 'Objeto para manejar la Tabla Es importante q tengan en cuenta lo q maneja cada objeto. Dijimos q el objeto BDD maneja la base de datos. Entonces podemos cargarla alli de la siguiente manera: Set BDD = OpenDatabase("c:\mis documentos\base1.mdb") 'Abre la base de datos Bueno, ahora q tenemos abierta la base de datos, vamos a realizar unas consultas utilizando ordenes SQL. Por lo tanto podriamos declarar una variable para almacenar nuestra sentencia SQL. Dim SQL As String Ya estamos listos para aplicar SQL... SENTENCIAS DE SELECCIÓN O CONSULTAS ACTUALIZAR LOS DATOS SENTENCIAS DE SELECCIÓN O CONSULTAS Bien, SQL permite realizar consultas mediante sentencias de selección "SELECT". Lo q hace esta sentencia SELECT es tomar datos de una base de datos para devolverlos a quien se lo pidió (en nuestro caso quien se lo pide es el objeto TBL). SELECT consta de seis cláusulas: las dos primeras obligatorias (SELECT y FROM) y las otras opcionales (WHERE, GROUP BY, HAVING, UNION, ORDER BY). SELECT y FROM FUNCIONES DE AGRUPAMIENTO WHERE GROUP BY HAVING UNION ORDER BY CONSULTAS A MAS DE UNA TABLA SELECT y FROM Veamos, con un ejemplo, como funciona: SQL = "SELECT * FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) 'TBL almacena todos los valores de la tabla Nuestra orden SQL es: seleccionar (SELECT) todos los campos (*) de (FROM) la tabla1. Ahora vamos a mostrar en la lista lo q almacenamos. TBL.MoveFirst 'nos posicionamos en el primer registro de la tabla Do Until TBL.EOF ''La propiedad EOF se pone TRUE cuando se a llegado al final de la tabla List1.AddItem TBL("nombre") TBL.MoveNext 'pasamos al siguiente registro Loop De esta manera, al ejecutar, nos debe aparecer en la lista todos los nombres de la tabla. Si queremos mostrar "nombre" "apellido": TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") TBL.MoveNext Loop Si queremos listar "nombre" "apellido" tiene "edad": TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop Qué sucede si solo quería tomar de la tabla1 los campos nombre y edad (no el apellido). En este caso la sentencia SQL quedaría: SQL = "SELECT nombre,edad FROM tabla1" Por lo tanto el formato de la sentencia SELECT hasta ahora es: SELECT campo1,campo2,...,campoN FROM nombre_de_la_tabla NOTA: si ya terminamos de trabajar con la tabla y con la base de datos las podemos cerrar de la siguiente manera: TBL.Close 'cierra tabla BDD.Close 'cierra base de datos FUNCIONES DE AGRUPAMIENTO Las funciones de agrupamiento son: DISTINCT: Dijimos q si usabamos el * nos seleccionaba todos los campos. También hay un operador llamado DISTINCT, éste elimina las filas o registros duplicados del resultado de la consulta. Esto se ve bien en el siguiente ejemplo: SQL = "SELECT DISTINCT edad FROM tabla1" 'almacena todas las edades sin repetirlas Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("edad") TBL.MoveNext Loop COUNT: Este operador nos devuelve la cantidad de valores en una columna. Por ejemplo, COUNT(nombre) devolverá el número de registros con valores no nulos en el campo nombre. Pero si usamos COUNT(*), nos devuelve el número de registros incluyendo aquellos registros con valores nulos. SQL = "SELECT COUNT(*) FROM tabla1" 'para saber la cantidad de registros (incluye los nulos) Set TBL = BDD.OpenRecordset(SQL) List1.AddItem TBL("expr1000") 'expr1000 es el name del item de TBL q almacena el resultado del operador de agrupamiento SUM: Devuelve la suma total de los valores de una expresión de columna o campo NUMERICA (si no es numerica les da error!) . Por ejemplo, SUM(edad) devolverá la sumatoria de las edades. SQL = "SELECT SUM(edad) FROM tabla1" 'sumatoria de las edades Set TBL = BDD.OpenRecordset(SQL) List1.AddItem TBL("expr1000") AVG: Devuelve el promedio de los valores de una expresión de columna. Por ejemplo, AVG(edad) devolverá el promedio de las edades. Esto seria dividir SUM(edad)/COUNT(edad). SQL = "SELECT AVG(edad) FROM tabla1" MAX: Devuelve el valor más alto de los contenidos en una expresión de columna. Si hacemos: SQL = "SELECT MAX(edad) FROM tabla1" Nos dirá la edad mas alta. MIN: Si hay un MAX, por q no puede haber un MIN? ya se habran dado cuenta lo q hace. Entonces, si SQL = "SELECT MIN(edad) FROM tabla1" Nos dirá la edad mas baja. EJEMPLO: quiero saber cuántos registro tengo, cual es la menor edad y cual es el promedio de todas las edades Dim BDD As Database Dim TBL As Recordset Dim SQL As String Set BDD = OpenDatabase("c:\mis documentos\base1.mdb") SQL = "SELECT COUNT(*), MIN(edad), AVG(edad) FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) List1.AddItem "total de reg: " & TBL("expr1000") List1.AddItem "MINIMA EDAD: " & TBL("expr1001") List1.AddItem "PROMEDIO EDADES: " & TBL("expr1002") TBL.Close BDD.Close WHERE Con WHERE indicamos condiciones para la selección de ciertos registros. Veamos un ejemplo: Antes q nada nuestra sentencia SELECT quedaría asi: SELECT campo1,campo2,...,campoN FROM nombre_de_la_tabla WHERE condicion1 AND condicion2 AND ... AND condicionN Dim BDD As Database Dim TBL As Recordset Dim SQL As String Set BDD = OpenDatabase("c:\mis documentos\base1.mdb") SQL = "SELECT * FROM tabla1 WHERE edad < 30" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("edad") TBL.MoveNext Loop TBL.Close BDD.Close Con esta instrucción decimos q: seleccione (SELECT) todos los campos (*) de (FROM) tabla1 q cumplan la condición (WHERE) edad < 30 GROUP BY Esta cláusula se utiliza para agrupar segun lo q especifiquemos. Por ejemplo, podemos listar todos los datos de nuestra tabla1, pero agrupados por edad. SQL = "SELECT edad, nombre, apellido FROM tabla1 GROUP BY edad,nombre, apellido" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop Entonces el formato es: GROUP BY expresion1, expresión2, ..., expresiónN. IMPORTANTE: Todas las expresiones deben coincidir con lo q pusimos en SELECT. Por lo tanto lo siguiente no funciona: SQL = "SELECT * FROM tabla1 GROUP BY edad,nombre, apellido" 'no se puede agrupar mediante los campos seleccionados con * SQL = "SELECT edad FROM tabla1 GROUP BY apellido" SQL = "SELECT nombre, apellido, edad FROM tabla1 GROUP BY edad" HAVING Asi como la cláusula WHERE especifica condiciones para la selección de registros, HAVING especifica condiciones para el agrupamiento (GROUP BY). Por lo tanto HAVING funciona solo si se especifica un GROUP BY. SQL = "SELECT edad, nombre, apellido FROM tabla1 GROUP BY edad,nombre, apellido HAVING edad<30" Con este ejemplo agrupamos según la edad, pero solo los q su campo edad es menos a 30. UNION Con este operador lo q hacemos es juntar dos resultados de dos sentencias SELECT diferentes. El resultado de la union son todos los registros devueltos en ambas sentencias, y los registros repetidos se omiten a no ser q utilicemos la palabra ALL. La forma es: SELECT sentencia1 UNION ALL SELECT sentencia2 con sentencia2 'sentencia1 debe coincidir veamos q sucede si hacemos lo siguiente SQL = "SELECT * FROM tabla1 UNION SELECT * FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop En este caso unimos la tabla1 con la misma tabla1, por lo tanto todos los resultados son repetidos y se omiten. Veamos q pasa con ALL SQL = "SELECT * FROM tabla1 UNION ALL SELECT * FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop Otra vez todos los datos se repiten pero en este caso le decimos q no omita ninguno, por lo tanto cada valor de la tabla1 estará repetido dos veces. Hacer esto no tiene sentido, es decir q la union debería ser con la selección de dos tablas diferentes. ORDER BY Para ordenar los resultados utilizamos ORDER BY. Cuando omitimos esta cláusula, los resultados se ordenan por el primer campo que sea clave en el índice que se haya utilizado. Veamos las siguientes sentencias: SQL = "SELECT * FROM tabla1 ORDER BY edad ASC" ' ordenado por edad en forma ascendente SQL = "SELECT * FROM tabla1 ORDER BY edad" ' ordenado por edad, por defecto lo ordena en forma ascendente SQL = "SELECT * FROM tabla1 ORDER BY edad DESC" ' ordenado por edad en forma descendente SQL = "SELECT * FROM tabla1 ORDER BY 1" 'ordenado por el primer campo de la tabla SQL = "SELECT nombre, apellido, edad FROM tabla1 ORDER BY 3,2,1" 'ordenado por edad, apellido y nombre Entonces podemos indicar el nombre_de_campo, número_de_campo y si es ASCendente o DESCendente. CONSULTAS A MAS DE UNA TABLA Supongamos q tenemos una base de datos con dos tablas llamadas tabla1 y tabla2. Tabla1 tiene como campos nombre, apellido y edad. Mientras q la tabla2 tiene nombre y email. Bien, por ejemplo yo podria querer los emails de las personas q estan en ambas tablas, esto es q el nombre de la tabla1 tiene q ser igual al nombre de la tabla2. Veamos como lo indicamos... SQL = "SELECT tabla1.nombre,email FROM tabla1,tabla2 WHERE tabla1.nombre=tabla2.nombre" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("email") TBL.MoveNext Loop Nuestra sentencia SQL quedo así: 1- Indicamos los campos a seleccionar (SELECT). Observar q el campo nombre aparece en las dos tablas, por lo tanto debemos indicar de q tabla los voy a seleccionar (tabla1.nombre). Por el contrario el campo email solo aparece en la tabla2, por lo tanto no hace falta indicarle de q tabla lo queremos ya q es obvio de cual va a ser. 2- Despues indicamos cuales tablas van a ser consultadas (FROM). Le indicamos q tabla1, tabla2. El orden es importante porq de cada registro de la primer tabla se efectua una busqueda en la segunda. 3- por ultimo indicamos la condición (WHERE). Decimos q el campo nombre de la tabla1 debe ser igual al de la tabla2. Ahora vamos a ver el mismo ejemplo pero usando ALIAS. Un alias es un nombre temporal q le asignamos a una tabla. Por ejemplo a la tabla1 la podemos llamar t1 y a la tabla2 t2. De esta manera es mas facil escribir t1 q tabla1. SQL = "SELECT t1.nombre,email FROM tabla1 t1,tabla2 t2 WHERE t1.nombre=t2.nombre" En el FROM escribimos nombre_tabla alias_tabla. En el resto de la sentencia usamos el alias en vez de el nombre. Ahora, supongamos q tenemos una tercer tabla q contiene nombre y telefono como campos. Queremos consultar los campos nombre, email y telefonos. SQL = "SELECT t1.nombre,email,telefono FROM tabla1 t1,tabla2 t2, tabla3 t3 WHERE t1.nombre = t2.nombre AND t1.nombre = t3.nombre" Lo importante de estas consultas es el orden en q se escriben las tablas luego del FROM, ya q esto va a influir en la velocidad de la consulta. Para terminar la sección de consultas vamos a ver las SELECT ANIDADAS. Esto es una SELECT dentro de otra. Es muy simple. Veamos un ejemplo. SQL = "SELECT t1.nombre,email,telefono FROM tabla1 t1,tabla2 t2, tabla3 t3 WHERE t1.nombre = t2.nombre AND t1.nombre = t3.nombre AND (SELECT COUNT(*) FROM tabla1)< 100" Es la misma condición anterior solo q se agrego una condición mas: (SELECT COUNT(*) FROM tabla1)< 100, esto es, q la tabla1 tenga menos de 100 registros. Entonces cuando insertamos una nueva SELECT dentro de otra, debemos ponerla entre parentesis. ORDENES PARA MODIFICAR DATOS UPDATE INSERT INTO DELETE UPDATE Podemos cambiar los datos q queramos en la tabla q queramos mediante la orden UPDATE. Por ejemplo, en la tabla1, donde teniamos nombre, apellido y edad. Supongamos q queremos q todas las edades se pongan a 0 (cero). Private Sub Form_Load() Dim BDD As Database Dim TBL As Recordset Dim SQL As String Set BDD = OpenDatabase("c:\mis documentos\base1.mdb") SQL = "UPDATE tabla1 SET edad = 0" BDD.Execute SQL SQL = "SELECT * FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop TBL.Close BDD.Close End Sub En este caso cambiamos la manera de trabajar, o mejor dicho, para la orden UPDATE trabajamos directamente sobre el objeto Database q almacena la base de datos donde queremos realizar el cambio. Para ejecutar una sentencia SQL podemos poner nombre_variable_database.Execute "sentencia_SQL" Veamos nuestra sentencia: actualizar (UPDATE) de la tabla1 las edades, ponerlas a cero (SET edad=0). Tambien podemos utilizar la orden WHERE para especificar algo mas preciso. Por ejemplo poner a cero las edades q sean mayores q 21. SQL = "UPDATE tabla1 SET edad = 0 WHERE edad>21" INSERT INTO Tambien podemos insertar nuevos registros. Para ello utilizamos la orden INSERT INTO. Veamos un ejemplo. En la tabla1 tengo los campos nombre, apellido y edad. Bien, ahora quiero agregar un nuevo nombre, apellido y edad. SQL = "INSERT INTO tabla1 (nombre,apellido,edad) VALUES('damian','sotto',22)" BDD.Execute SQL Bien, primero decimos insertar en la tabla1 (INSERT INTO tabla1) nuevos valores para los campos (nombre, apellido,edad) los valores son para el primer campo damian, para el segundo sotto y para el tercero 22. En VALUES se escriben los valores de los campos en el mismo orden en q se especificaron. Los caracteres van entre ' ' y las fechas entre {}. Si no especificamos valores entonces el campo queda vacio. Pero si o si debe haber un valor para poder crear un nuevo registro. Bueno, ya sabemos como actualizar datos y como agregar datos. Ahora nos falta como eliminar datos. DELETE Esta sentencia se utiliza para borrar los registros de una tabla. La sentencia es DELETE FROM nombre_tabla WHERE condiciones. SQL = "DELETE FROM tabla1 WHERE edad<21" BDD.Execute SQL Con esta sentencia borro todos los registros cuya edad sea menor a 21. Si no especifico un WHERE, se borran todos los registros, o sea, la tabla me queda vacia. SQL = "DELETE FROM tabla1" BDD.Execute SQL Ahora, si la tabla esta vacia, cuando hagamos una busqueda dentro de ella el programa va a dar error. Una solución sería: SQL = "SELECT * FROM tabla1" Set TBL = BDD.OpenRecordset(SQL) If TBL.EOF Then ''EOF esta en verdaero si no hay datos MsgBox "No hay datos que coincidan con la búsqueda especificada" Exit Sub End If 'si llega hasta aca es porq hay datos TBL.MoveFirst Do Until TBL.EOF List1.AddItem TBL("nombre") & " " & TBL("apellido") & " tiene " & TBL("edad") TBL.MoveNext Loop TBL.Close BDD.Close