Download Índice General - Instituto Wiener

Document related concepts
Transcript
INSTITUTO SUPERIOR TECNOLÓGICO
NORBERT WIENER
Manual del Alumno
ASIGNATURA: Lenguaje de Programación II
(Visual Basic II)
PROGRAMA: S3C
LIMA-PERU
2
Manual del Alumno
Índice General
Pag N°
1. Introducción y base de datos....................................................................................... 2
2. Control Ado ............................................................................................................... 4
3. El Control Ado Data Control 6.0 (OLEDB)................ .............................................. 8
4. El Control Ado Data Control 6.0 (OLEDB)(continuación)....................................... 44
5. El Control Ado Data Control 6.0 (OLEDB)(continuación)....................................... 50
6. Controles Enlazados .................................................................................................. 56
7. Uso de Múltiples Tablas ............................................................................................ 57
8. Uso de Múltiples Tablas (continuación)..................................................................... 58
9. El Data Environment ..................................................................................................63
10. Visual Basic – SQL ................................................................................................... 69
11. Controles no Enlazados ..............................................................................................70
12. Controles no Enlazados y Módulo de Clase................................................................78
13. Controles Active X......................................................................................................86
14. Funciones Api’s.........................................................................................................91
3
Manual del Alumno
INTRODUCCION Y BASE DE DATOS
Acceso a Datos:
Los datos se consideran uno de los activos más valiosos de la empresa moderna. Por
tal razon, es importante que la misma cuente con una estrategia apropiada para
administrarlos adecuadamente; esto es, almacenarlos, recuperarlos y procesarlos de tal
forma que sean importantes para la toma de decisiones.
Visual Basic provee soporte a datos de muchas maneras. Se puede utilizar DAO (Data
Access Objects) para manipular datos provenientes de Microsoft Jet o Access o Excel,
ODBC (Open Database Conectivity), ISAM y tecnologís RDO (Remote Data Object) y
ADO (Actives Data Object).
Los Objetos de acceso a datos (DAO) y el control Data utilizan el motor de base de
datos Microsoft Jet para tener acceso a las bases de datos. El motor de base de datos Jet
puede obtener acceso a tres tipos de bases de datos:
® Bases de datos Microsoft Jet:
Es un motor utilizado por Microsoft Access y Visual Basic. Este motor permite crear
y manipular datos directamente.
® Bases de datos del Método de acceso secuencial indizado (ISAM, Indexed
Sequential Access Method):
Dada la existencia de formatos conocidos y extendidos mundialmente, como por
ejemplo, Btrieve, dBase, Microsoft Visual FoxPro, Paradox, entre otros, DAO
permite la manipulación de datos de éstos formatos.
® Bases de datos compatibles con Open Database Connectivity (ODBC,
Conectividad abierta de bases de datos):
No solo las bases de datos de escritorio o denominadas “desktop” tienen soporte por
parte de DAO. Las bases de datos del estilo cliente/servidor que se ajustan al estándar
ODBC, tal como SQL Server, Oracle u otros a los cuales se diseñó su apropiado
“provider” se le da soporte.
Visual Basic también provee otros métodos de acceso a datos, tal y como:
® Control de origen de datos remotos
En la edición empresarial de Visual Basic se dispone de un control de origen de datos
remotos, que soportan ODBC, tal como Microsoft SQL Server y Oracle.
4
Manual del Alumno
® Bibliotecas ODBC
Le permiten llamar directamente a la interfaz de programación de aplicaciones (API)
de ODBC. Está disponible como un producto independiente.
® Bibliotecas SQL para Visual Basic (VBSQL)
Proporcionan un vínculo directo a Microsoft SQL Server. Están disponibles como
productos independientes.
Descripción de una Base de Datos:
Hoy día la mayoría de sistemas informáticos que administran la información de una
empresa utilizan un esquema relacional. Esto es, relacionan logicamente la información
utilizando tablas y entidades que conforman llaves de enlace.
Un esquema relacional presenta los datos como un grupo de tablas que se relaciona
logicamente entre si. Por ejemplo, Visual Basic provee la base de datos Biblio.Mdb y en
ella radican varias tablas de datos (tales como author y titles) que se relacionan entre si
gracias a la duplicacion que existe en ellas del ID u otros campos.
Se puede observar el diagrama de base de datos denominada Students And Classes
elaborada mediante asistente en Visual Foxpro, versión 6.0. Observense los campos,
índices y relaciones contenidos:
Elementos de una tabla:
La base de datos Students and classes contiene varias tablas que agrupan
información, como studentes, assigments, results, entre otras.
En una base de datos, las filas de tablas se denominan registros o tuplas y las
columnas campos. Los registros pertenecen a la descripción de una entidad, por ejemplo,
un cliente, un proveedor, un empleado, un producto, entre otros. Por otro lado, el campo
5
Manual del Alumno
es parte del registro como puede ser la cedula, el nombre, la existencia, la direccion, el
telefono, entre otros. Asimismo, existen índices (que pueden ser de diferentes tipos) y
reglas (reglas de validación y de integridad referencial).
Clave principal:
Cada tabla contenida en una base de datos posee una clave principal. Esta es un
campo, o la combinación de varios campos, que es exclusiva en cada fila de la tabla. Esto
permite identificar de forma uniequivocamente un registro particular, permitiendo que no
existan registros duplicados o accesar más rapidamente a un registro o a una colección de
ellos. En el caso de la base de la base de datos Students and classes, se tiene una tabla
denominada students, donde la clave primaria es studentid, dado que la identificación de
todos y cada uno de los estudiantes es única en la colección de registros. Asimismo, en la
tabla results se tiene una clave por el mismo campo, siendo una llave que se puede repetir
tantas veces como sea necesaria, dado que un estudiante puede registrar todos los resultados
obtenidas por materia. En este caso se determina una clave externa, dado que la misma no es
propia de la tabla sino de otra que es students.
Registros:
Un registro contiene información referente a una entrada a una tabla. Es preferible
que una tabla no contenga duplicados. En este caso es una tabla maestra. En el caso de la
tabla Students, es necesario que cada estudiante tenga su propio Id y no exista otro similar en
la tabla. Sin embargo, en registros históricos se repetirá tantas veces una llave como sea
necesario.
Campos:
Un campo de una tabla identifica una parte de un registro. Por ejemplo, la tabla
students contiene los campos studentid, lastname y firstname, entre otros.
Indices:
Los indices de una tabla son listas ordenadas en las que se puede localizar más
rápidamente un determinado registro o conjunto de ellos. Se crean en base a un campo de
la tabla, tomando como requerimiento cuál de ellos representa una entidad fuerte dentro de
la colección o cuál es el adecuado para ordenar un conjunto de registros.
Conectividad a datos en Visual Basic:
Existen dos métodos para abrir una base de datos en Visual Basic: utilizando el Data
Control (el cual es un objeto provisto por Visual Basic) o mediante el método OpenDatabase.
El control data es un objeto provisto por Visual Basic para la manipulación de datos en una o
varias tablas.
El control data implementa este acceso mediante la utilización de un motor de bases de
datos tal como Microsoft Jet. Existen métodos apropiados para la manipulación de datos y
se provee de una herramienta de generación automática de formularios que se encarguen de
dicha manipulacion, sin necesidad de escribir mucho código.
6
Manual del Alumno
Para construir una aplicación de bases de datos, utilizando el control data, se
recomienda seguir los siguientes pasos:
1. Agregar un control data al formulario y configurar las propiedades Databasename,
connect y recordsource, principalmente. Lo anterior para establecer la base de
datos a la que se va a conectar el formulario, el tipo de conexión (por defecto es
Microsoft Access) y el origen de datos (la tabla de la base de datos abierta).
2. Agregar controles tales como text box o label para que contengan los datos del
recordsource. Aqui hay que configurar datasource y datafield como las
propiedades que se conectarán a los datos del data control.
Usar controles enlazados a datos:
Cuando se utiliza un data control en un formulario generalmente es necesario diseñar
controles que permitan contener los datos cargados en dicho data control. Estos controles
pueden ser CheckBox, Image, Label, PictureBox, TextBox, ListBox, ComboBox y los
contenedores OLE.
Propiedades y Métodos del Control Data:
Además de las propiedades Databasename y RecordSource el data control posee otras
propiedades y métodos, tales como:
® Propiedad Connect
® Propiedad Exclusive
® Propiedad ReadOnly
® Propiedad Recordset
® Propiedades BOFAction y EOFAction
® Método Refresh
La Propiedad connect especifica el tipo de base de datos que se abrirá. Puede incluir
argumentos tales como Id de usuario y la contraseña.
La propiedad Exclusive determina si la base de datos será abierta en forma exclusiva o
no. Si el valor de esta propiedad es True la base de datos se abrirá exclusivamente y
ninguna aplicación podrá utilizarla hasta que se cierre.
La propiedad ReadOnly determina si la base de datos se abrirá para solo lectura o no.
Si la propiedad es True no se podrán modificar los datos obtenidos.
El objeto Recordset contiene los registros devueltos para el data control, basado en
una apertura de una tabla o producto de la ejecución de una instruccion SQL. Un recordset
tiene propieades y metodos que se pueden utilizar para trabajar con los registros obtenidos.
Las propiedaes BOFAction y EOFAction determinan que acción realizar cuando las
propiedades BOF o EOF del Recordset son True. Por ejemplo, si la propiead EOFAction
del control data es vbAddNew y utiliza el control data para situarse trás el último registro del
recordset, el control data ejecutará automáticamente el metodo AddNew para incluir un
nuevo registro.
7
Manual del Alumno
El método Refresh actualiza un objeto recordset. Si se cambia la propiedad
RecordSource del data control, se deberá llamar a este método para actual el conjunto de
registros en el data. Lo siguiente es un ejemplo de lo anterior:
Data1.RecordSource = "SELECT * FROM Empleados " & _
"WHERE [IdEmpleado] = " & txtEmpID.text
Data1.Refresh
Recordset:
Es el conjunto de registros contenidos en el control data. Un Recordset se almacena
en la memoria, transfiriendo los datos contenidos al disco, si fuera necesario.
Para manipular un Recordset debe utilizarse la propiedad del mismo nombre del data
control.
Para determinar los límites de un Recordset se utilizan las propiedades EOF y BOF.
Cuando se desplace al último registro (EOF) o al inicio del archivo (BOF), se ejecutará la
acción indicada por el valor de la propiedad BOFAction o EOFAction. Seguidamente se
muestra como Microsoft grafica estas propiedades:
Asimismo, se muestra como utilizar un objeto Recordset de un determinado control
Data:
Data1.Recordset.MoveNext 'Va al registro siguiente.
If Data1.Recordset.EOF Then
Data1.Recordset.MoveLast
End If
El ejemplo anterior muestra como desplazarse al registro siguiente en el Recordset y
posteriormente validar si se ha llegado al final del mismo.
Se pueden utilizar otros métodos y propiedades del objeto Recordset para recuperar,
agregar, modificar o eliminar registros de este objeto.
Las propiedades BOF y EOF del objeto Recordset indican si el registro actual está
al inicio o al final del Recordset, respectivamente. Si lo anterior es verdadero, se asignará
True a la propiedad respectiva. Si ambas son verdaderas es que no existen datos en el
Recordset.
8
Manual del Alumno
Método AddNew:
El metodo AddNew de un objeto Recordset se utiliza para agregar un nuevo registro.
Cuando se ejecuta este metodo, Visual Basic elimina los controles enlazados y asigna a la
propiedad EditMode del control data el valor dbEditAdd.
Para actualizar un registro en el Recordset luego de utilizar AddNew debe utilizarse el
método UpdateRecord o Update. Lo siguiente muestra este aspecto:
Sub cmdAdd_Click ()
Data1.Recordset.AddNew
End Sub
Metodo UpdateRecord:
El método UpdateRecord se utiliza para guardar el registro actual en una base de
datos. Es decir, posterior al metodo AddNew, tal y como se muestra a continuación:
Sub cmdUpdate_Click ()
Data1.UpdateRecord
End Sub
Metodo CancelUpdate:
Se utiliza para cancelar un método AddNew o Edit y actualizar los controles enlazados
al control data. Es decir, restaura los datos originales del Recordset. A continuación se
muestra el uso de este método:
Sub cmdCancel_Click ()
Data1.CancelUpdate
End Sub
Metodo CancelUpdate:
Este método se utiliza para eliminar un registro de una tabla. El registro eliminado
continuará siendo el actual hasta tanto el usuario no realice ninguna otra acción, tal y como
se muestra en el codigo siguiente:
Sub cmdDelete_Click ()
Data1.Recordset.Delete
Data1.Recordset.MoveNext
If Data1.Recordset.EOF Then
Data1.Recordset.MoveLast
End If
End Sub
9
Manual del Alumno
Usando Objetos Recordset
Un recordset es un objeto que presenta los registros de una tabla o el resultado de una
consulta. Se pueden usar objetos para manipular los datos de una base de datos a un nivel
de registro.
Se puede usar objetos “Field” para manipular los datos de un archivo a un nivel de
registro.
Los cuatro tipos de recordset son:
 Table,
 Dynaset,
 Snapshot y
 Forward-Only
Table: Este Recordset puede ser creado para una tabla Microsoft Access, pero no
soporta ODBC (Open Database Connectivity) o tablas ligadas. Es decir,
funciona para una sola tabla de Microsoft Access. Cuando se crea una tabla,
el motor de bases de datos JET abre dicha tabla y subsecuentemente se
produce la manipulacion de los datos, operando directamente sobre la misma.
Una ventaja importante de este tipo de recordset es que se puede utilizar un
indice. Esto hace más eficiente la ordenacion de registros mediante un índice,
mejorando significativamente las opciones de búsqueda. Para localizar un
determinado registro se puede utilizar el metodo SEEK y no FIND, dado que
este ultimo es mucho más lento.
Dynaset:Este recordset puede crearse sobre una o varias tablas, mediante consultas.
Esto es mediante un conjunto de referencias a registros en una o más tablas.
Con un dynaset, se pueden extraer y actualizar datos desde una o varias tablas,
incluyendo las ligas que puedan existir con otras bases de datos. La
actualizacion heterogenea es una caracteristica importante de los dynaset.
Uno de los más importantes beneficios es que los cambios realizados sobre
una tabla se realizan tambien en otra que se encuentra ligada a ésta.
Asimismo, los cambios hechos por otros usuarios se reflejan en el dynaset.
El dynaset es el más flexible y poderoso de los demás tipos de recordset, sin
embargo es mucho más lento que, por ejemplo, el tipo table.
Snapshot:Este recordset es una copia estática de un conjunto de registros, capturados
en el momento de crearse el recordset. Este puede contener campos de una o
más tablas de una base de datos. Este recordset es actualizable.
La principal ventaja de un snapshot es que éste crea menos “overhead” en el
procesamiento que los demás recordset. Además se pueden ejecutar consultas
y retornar los valores más rápidamente, especialmente cuando se trabaja con
ODBC.
Se debe considerar que para archivos MDB, OLE y archivos memo son
direccionados por punteros en la consulta.
10
Manual del Alumno
Forward-Only: Este tipo de recordset (muchas veces denominado forward-scrolling
snapshot o forward-only snapshot) provee un subconjunto de capacidades de
un snapshot. Con este objeto se puede mover solo en dirección adelante a
traves de registros. Solo se soporta los metodos Move o Move Next. La
ventaja de este tipo de recordset es que usualmente provee la mayor velocidad
entre los demas recordset. Sin embargo, ofrece la menor funcionalidad que
los demas.
Un Snapshot almacena una copia de todos los registros (excepto objetos OLE
y campos memo).
Un Dynaset almacena justamente la llave primaria para cada registro,
copiando la totalidad de registros solo cuando es necesario para edicion o
propositos de despliegue. Desde un snapshot almacena una copia completa de
todos los registros en una tabla, éste puede rendir más lentamente que un
dynaset si el numero de registros es muy cuantioso. Para determinar cuando
usar un dynaset o un snapshot se pueden abrir ámbos, ejecutar la misma
consulta y comparar los tiempos de respuesta.
El tipo de recordset que se use depende de lo que el usuario debe hacer con los
datos. Puede que solo desee realizar una vista o que además deba
actualizarlos. Por ejemplo, si el usuario desea ordenar los datos o trabajar
con indices, usese un tipo table, dado que estos estan indexados y son más
rapidos de localizar. Otro caso es que si el usuario desea actualizar un
conjunto de registros seleccionados por una consulta, debe usarse el dynaset.
Finalmente, si la tabla que se desea consultar pocas veces está disponible y se
desea realizar una busqueda en un conjunto de registros determinados puede
usarse un tipo forward-only.
Creando una variable objeto:
Para crear una variable objeto, debe usarse el método OpenRecordset. Primero debe
declararse el tipo de variable y el grupo de variables para el objeto, retornado por el metodo
OpenRecordset. Puede usarse el método OpenRecordset con Database, TableDef,
QueryDef, y objetos existentes.
La sintaxis del método OpenRecordset es:
Set variable = database.OpenRecordset (source [, type [, options [, lockedits ]]])
La sintaxis del método OpenRecordset para todos los tipos de objetos es:
Set variable = object.OpenRecordset ([type [, options [, lockedits ]]])
11
Manual del Alumno
La argumento variable es el nombre del nuevo objeto. El argumento database es el nombre
del objeto de base de datos abierto. El argumento Object es el TableDef, QueryDef, o el
objeto existente.
El argumento source especifica el origen de los registros para el nuevo objeto. El valor
del origen es el valor del objeto DAO. Cuando se crea un nuevo objeto desde un objeto
Database el argumento source es un TableDef o QueryDef en la base de datos o un retorno
válido de una consulta SQL o sentencia. Cuando se crea un objeto de este tipo el mismo
provee el origen de datos para el nuevo objeto.
El argumento type es una constante intrinseca que especifica la clase de objeto que se
desea crear. Se pueden utilizar las siguientes constantes:




dbOpenTable
dbOpenDynaset
dbOpenSnapshot
dbOpenForwardOnly
El tipo de constante dbOpenForwardOnly reemplaza al tipo de constante
dbForwardOnly que estaba contenida en versión posterior de DAO. Es decir, esta
constante se mantiene por compatibilidad con la version anterior de DAO.
La siguiente sección muestra los tipos, opciones y argumentos de “lockedits” en detalle:
Tipos por defecto:
Porque DAO automaticamente escoge el tipo por defecto, dependienteo del origen de
datos y como se realiza la apertura, no se necesita especificar el tipo. Sin embargo, se puede
especificar un tipo diferente usando el argumento type en el metodo OpenRecordset.
La lista siguiente describe los tipos disponibles y los tipos por defecto, dependiendo de
cómo se abra el objeto:

Usando el método OpenRecordset con un objeto Database
Set rstNew = dbs.OpenRecordset("Data Source")
Si el recurso de datos es una tabla local en la base de datos, los cuatro tipos estan
disponibles y el tipo table está por defecto.
Si el origen de datos es diferente, solo
Dynaset y Snapshot estan disponibles. Dynaset es el default.

Usando el método OpenRecordset con un objeto TableDef:
12
Manual del Alumno
Set rstNew = tdfTableData.OpenRecordset

Si tdfTableData se refiere a una tabla de Microsoft Access (*.mdb) o ISAM abierta
directamente, entonces los cuatro tipos estan disponibles. Si tdfTableData es un base
de datos abierta mediante ODBC o es una tabla ligada en una tabla externa, solo los
tipos dynaset y snapshot estan disponibles.
Usando el método OpenRecordset con un objeto QueryDef:
Set rstNew = qdfQueryData.OpenRecordset

Solo los objetos dynaset y snapshot estan disponibles.
Usando el método OpenRecordset con un objeto existente:
Set rstNew = rstExisting.OpenRecordset
Solo los objetos dynaset y snapshot estan disponibles.
Opciones OpenRecordset:
Con el argumento Options del metodo OpenRecordset se puede especificar un numero
de otras caracteristicas para un objeto. Se pueden utilizar las siguientes constantes:








DbAppendOnly: Los usuarios pueden agregar nuevos registros, pero no se puede
editar o eliminar. Esto es util en aplicaciones que capturan y archivan muchos datos
(solo dynaset).
DbReadOnly: No se pueden hacer cambios. Este argumento es proveido solo por
compatibilidad de versiones anteriores. Se debe utilizar la constante dbReadOnly en
el argumento lockedits para ello.
DbSeeChanges: Si otro usuario realiza cambios en los datos en los registros (con edit
y update) se produce un error en tiempo de ejecucion. Esto es util en aplicaciones
donde multiples usuarios realizan, simultaneamente, operaciones de lectura/escritura
sobre los mismos datos (solo dynaset y table).
DbDenyWrite: Cuando se usa con dynaset o snapshot, esta opcion previene a otros
usuarios de inserciones o modificaciones de registros. Cuando una tabla está en uso
otros usuarios no pueden abrir ningun otro tipo de recordset.
DbDenyRead: Otros usuarios no pueden leer datos en la tabla (solo tabla)
DbForwardOnly: Esta opcion crea un recordset forward-only o snapshot. Este es
proveido solo por compatibilidad con versiones anteriores. Use la constante
dbOpenForwardOnly en el argumento type.
DbSQLPassThrough: Cuando el argumento source es una sentencia SQL, use esta
constante para pasar las sentencias SQL a una base conectada via ODBC, para
procesamiento. Si la usa con un dynaset, los datos no son actualizables (dynaset y
snapshot solamente).
dbConsistent (Default): Solo consiste en actualizaciones (solo dynaset). Se puede
usar esta constante con la constante dbInconsistent.
13
Manual del Alumno

DbInconsistent: Son permitidas actualizaciones inconsistentes. Esta es la contraria
de dbConsistent (solo dynaset). No se puede usar esta constante con la constante
dbConsistent.
Con el argumento lockedits del metodo OpenRecordset se puede controlar como
bloquear un objeto. Se pueden utilizar las siguientes constantes:



DbReadOnly: No se pueden realizar cambios. Esta constante reemplaza a la
constante dbReadOnly que fue usada en el argumento options en versiones
anteriores de DAO.
dbPessimistic (Default): Microsoft Jet usa bloqueo pesimista para determinar como
los cambios pueden ser hechos en un ambiente multiusuario.
DbOptimistic: Microsoft Jet usa bloqueo optimista para determinar como los
cambios pueden ser hechos en un ambiente multiusuario.
El valor por defecto es dbPessimistic. El solo efecto de usar dbPessimistic o
dbOptimistic es para configurar el valor de los objetos con la propiedad LockEdits.
14
Manual del Alumno
Creando un Objeto desde un Formulario:
Usted puede crear un objeto Recordset basado en un formulario de Microsoft Access.
Para hacer esto, use la propiedad RecordsetClone del formulario. Este crea un Recordset
tipo dynaset que se refiere a la misma consulta o “data” del fomulario. Si el formulario está
basado en una consulta, hay que referirse a la propiedad RecordsetClone. Esto es el
equivalente a crear un dynaset con la misma consulta. Se puede utilizar la propiedad
RecordsetClone cuando necesite aplicar un metodo provisto de acceso a todos los metodos y
propiedades que se pueden utilizar con un dynaset. La sintaxis para la propiedad
RecordsetClone es:
Set variable = form.RecordsetClone
El argumento variable es el nombre de un objeto Recordset existente. El argumento
form es el nombre de un formulario Microsoft Access. El siguiente ejemplo muestra como
asignar a un objeto Recordset los registros en el formulario “Orders”:
Dim rstOrders As Recordset
Set rstOrders = Forms!Orders.RecordsetClone
Este codigo siempre crea el tipo de Recordset siendeo cloneado (el tipo de Recordset
basado en el formulario); otros tipos no están disponibles.
Creando un Objeto desde una Tabla:
El metodo que se use para crear un objeto Recordset desde una tabla depende de si la
tabla es local a la base de datos actual o si está ligada a otra tabla en otra base de datos. La
siguiente discusion explica las diferencias y provee de ejemplos para cada tipo de tabla:
Creando un Recordset desde una tabla en una base de datos local Microsoft Access:
El siguiente ejemplo usa el metodo OpenRecordset para crear una tabla tipo
Recordset:
Objeto para una tabla en la base de datos actual:
Dim dbs As Database, rstCustomers As Recordset
Set dbs = CurrentDb
Set rstCustomers = dbs.OpenRecordset("Customers")
Notese que no es necesario usar la constante dbOpenTable para crear una tabla de tipo
Recordset. Si se omite la constante type DAO selecciona el tipo de Recordset de mayor
funcionalidad, dependiendo del objeto, en cuanto el Recordset creado y el origen de datos.
Para cuando el tipo de tabla está disponible y se abre un Recordset, DAO usa
automáticamente este tipo.
15
Manual del Alumno
Creando un Recordset desde una tabla ligada a una tabla de un formato diferente:
El siguiente ejemplo crea un Recordset de tipo dynaset, para una tabla Paradox® 3.X.
Pero el tipo tabla no está disponible cuando se abre un Recordset desde una tabla ligada a
una base de datos que no sea Microsoft Access. DAO selecciona el tipo próximo de
Recordset que sea más eficiente:
Dim dbs As Database
Dim tdf As TableDef
Dim rstTableData As Recordset
' Obtiene la base de datos activa.
Set dbs = CurrentDb
Set tdf = dbs.CreateTableDef("PDXAuthor")
' Conecta a la base de datos la tabla Paradox Author.
' C:\PDX\Publish.tdf.Connect = "Paradox 3.X;DATABASE=C:\PDX\Publish"
tdf.SourceTableName = "Author"
' Liga la tabla.
dbs.TableDefs.Append tdf
' Crea un Recordset tipo dynaset-type para la tabla.
Set rstTableData = tdf.OpenRecordset()
Se puede abrir directamente una tabla Paradox, abriendo inicialmente la base de datos
Paradox.
Usando un Indice en un Recordset de tipo tabla:
Se pueden ordenar registros en un Recordset de tipo “table” configurando la propiedad
Index. Cualquier objeto Index en la colección Indexes para los objetos tipo Recordset
pueden ser especificados en la propiedad Index.
El ejemplo siguiente crea un Recordset de tipo “table” basado en la tabla Customer y
utilizando un indice existente llamado City:
Dim dbs As Database, rstTableData As Recordset
Set dbs = CurrentDb
Set rstTableData = dbs.OpenRecordset("Customers", dbOpenTable)
' Mueve el puntero al primer registro de la tabla
rstTableData.MoveFirst
' El primer registro sin indice
MsgBox rstTableData!CompanyName
rstTableData.Index = "City"
' Selecciona el indice City.
rstTableData.MoveFirst
‘ Mueve el puntero al primer registro.
MsgBox rstTableData!CompanyName
rstTableData.Close
Si se utiliza la propiedad Index para un indice que no existe, un error de ejecucion
capturable ocurre. Si se desea ordenar registros de acuerdo a un índice que no existe, se
16
Manual del Alumno
puede crear el indice primero o crear un Recordset de tipo dynaset o snapshot, usando una
consulta que retorne registros en un orden establecido.
Es importante utilizar la propiedad Index antes de usar el metodo Seek.
Creando un objeto Recordset desde una consulta:
Se puede crear un objeto Recordset basado en una consulta almacenada o no. En el
siguiente ejemplo se muestra la lista de productos en una consulta almacenada en la base de
datos activa:
Dim dbs As Database, rstProducts As Recordset
Set dbs = CurrentDb
Set rstProducts = dbs.OpenRecordset("Current Product List")
Si la consulta almacenada no existe, el metodo OpenRecordset tambien acepta una
cadena SQL. El ejemplo anterior puede ser reescrito tal como sigue:
Dim dbs As Database, rstProducts As Recordset
Dim strQuerySQL As String
Set dbs = CurrentDb
strQuerySQL = "SELECT * FROM Products WHERE Discontinued = No " _
& "ORDER BY ProductName;"
Set rstProducts = dbs.OpenRecordset(strQuerySQL)
La desventaja de esta última es que la consulta basada en una cadena debe ser
compilada cada vez que se ejecuta, mientras que una almacenada solo lo hace la primera
vez. Esto mejora el rendimiento.
Cuando se crea un objeto Recordset, usando una cadena SQL o una consulta
almacenada, el codigo de la misma no necesita seguir ejecutandose hasta que la consulta
retorna la primera fila en el Recordset.
Ordenando y Filtrando Registros:
Si se utiliza un Recordset de tipo “Table” y se utiliza la propiedad Index se puede estar
seguro que los registros apareceran en un orden especifico. Sin embargo, usualmente se
necesita extraer registros en un especifico orden en otro tipo de Recordset. Por ejemplo, se
puede necesitar visualizar las facturas ordenadas por número, o clientes en orden alfabetico.
Para ordenar los registros en un objeto Recordset que no es una tabla, utilice la claúsula
Order By en la consulta. Tambien se puede filtrar los datos mediante la utilización de la
claúsula Where
El siguiente ejemplo muestra el uso de ámbos:
Dim dbs As Database, rstManagers As Recordset
Set dbs = CurrentDb
17
Manual del Alumno
Set rstManagers = dbs.OpenRecordset("SELECT FirstName, LastName FROM " _
& "Employees WHERE Title = 'Sales Manager' ORDER BY LastName")
Una desventaja de ejecutar una consulta SQL en un metodo OpenRecordset es que
éste deventaja de ser precompilado cada vez que se ejecuta. Por ende, si la consulta es usada
frecuentemente, se obtiene mayor rendimiento creando un procedimiento almacenado usando
la misma consulta y abriendo un objeto Recordset cada vez que se requiera la consulta, tal y
como se muestra a continuacion:
Dim dbs As Database
Dim rstSalesReps As Recordset
Dim qdf As QueryDef
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef("SalesRepQuery")
qdf.SQL = "SELECT * FROM Employees WHERE Title = 'Sales Representative';"
Set rstSalesReps = dbs.OpenRecordset("SalesRepQuery")
Para una mayor flexibilidad y control en tiempo de ejecucion se pueden usar
parametros para determinar criterio de orden y filtro.
Recreando a consulta desde un objeto Recordset:
Se puede utilizar un objeto Recordset abierto desde un QueryDef creando un objeto
de este tipo.
Para hacer esto, se debe utilizar el metodo CopyQueryDef. Este es
usualmente utilizado en situaciones donde un la variable de un objeto Recordset creado
desde un objeto QueryDef es pasado a una funcion y ésta debe recrear el SQL equivalente a
la consulta y posiblemente modificarla.
Modificando una Consulta desde un objeto Recordset:
Se puede utilizar el metodo Requery en un Recordset de tipo dynaset o snapshot
cuando se requiere ejecutar una consulta cada vez que se cambian los parametros. Esto es
más conveniente que abrir un nuevo Recordset y se ejecuta más velozmente.
El siguiente ejemplo crea un objeto Recordset y llama a una funcion que usa el
metodo CopyQueryDef para extraer la cadena correspondiente a la consulta SQL. Este
entonces dispone al usuario para que pueda utilizar los parametros de la consulta. El codigo
usa el metodo Requery para ejecutar la consulta modificada por el usuario:
Sub AddQuery()
Dim dbs As Database
Dim qdf As QueryDef
Dim rstSalesReps As Recordset
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef("SalesRepQuery")
qdf.SQL = "SELECT * FROM Employees WHERE Title = 'Sales Representative'"
set rstSalesReps = qdf.OpenRecordset()
18
Manual del Alumno
'Llama a la funcion para agrear el constraint.
AddQueryFilter rstSalesReps
' Retorna a la base de datos original.
dbs.QueryDefs.Delete "SalesRepQuery"
rstSalesReps.Close
End Sub
Function AddQueryFilter(rst As Recordset)
Dim qdf As QueryDef
Dim strNewFilter As String, strRightSQL As String
Set qdf = rst.CopyQueryDef
'"LastName LIKE 'D*'".
strNewFilter = InputBox("Digite nuevo criterio : ")
strRightSQL = Right(qdf.SQL, 1)
' Quita caracteres desde el final de la consulta, como sea necesario.
Do While strRightSQL = " " Or strRightSQL = ";" Or strRightSQL = vbCR Or _
strRightSQL = vbLF
qdf.SQL = Left(qdf.SQL, Len(qdf.SQL) - 1)
trRightSQL = Right(qdf.SQL, 1)
Loop
qdf.SQL = qdf.SQL & " AND " & strNewFilter & ";"
rst.Requery qdf
' Reconsulta el Recordset.
rst.MoveLast
' llena el Recordset.
' "Lastname LIKE 'D*'" podría retornar 2 registros.
MsgBox "Número de Registros encontrados = " & rst.RecordCount
End Function
Para usar el metodo Requery, la propiedad Restartable del objeto Recordset debe
estar en True. La propiedad Restartable es simpre True cuando el Recordset es creado
desde una consulta. No se puede reiniciar consultas pass-through. Se puede o no tener
disponibilidad para reiniciar consultas con tablas ligadas en otro formato de base de datos,
sino es la nativa Microsoft Access. Para determinar cuando un objeto puede reejecutar una
consulta chequee la propiedad Restartable.
Ordenamiento DAO y propiedades de filtro.
Otra manera de ordenar y filtrar objetos Recordset está para configurar las
propiedades de ordenamiento y filtrado del objeto DAO. Sin embargo, este es usualmente
más lento que incluir un criterio de ordenamiento o filtrado en la consulta original o
cambiando los parametros y ejecutando este de nuevo con el metodo Requery. Las
propiedades de ordenamiento y filtrado de DAO son usualmente utilizadas cuando se
necesitar utilizar un conjunto de resultados para un usuario, pero el origen de los datos no
está disponible para una nueva consulta. Por ejemplo, cuando un objeto Recordset tiene mas
de 100 registros. Usar el metodo CopyQueryDef es preferible para cuando esa cantidad es
inferior.
19
Manual del Alumno
Moviendose a traves de objetos Recordset:
Un objeto Recordset usualmente tiene una posición actual, a menudo es un registro.
Cuando se refiere a un campo en el RecordSet, se obtienen valores desde el registro en la
posicion actual. Sin embargo la posicion actual puede tambien ser la siguiente o la anterior.
En ciertos casos, la posicion actual es indefinida.
Se puede utilizar los siguientes métodos Move para movilizarse a traves de los
registros de un Recordset:





MoveFirst mueve al primer registro.
MoveLast mueve al último registro.
MoveNext mueve al registro próximo.
MovePrevious mueve al registro anterior.
Move [n] mueve n registros hacia delante.
Se pueden usar cualquiera de estos métodos en un Recordset de tipo Table, Dynaset o
Snapshot. En el tipo Forward-Only solo se puede usar el MoveNext y se pueden especificar
la cantidad de registros que se desea desplazar.
El siguiente ejemplo abre un objeto Recordset utilizando la tabla “Employees”, la cual
contiene todos los registros que tienen un valor Null en el campo ReportsToField. La
función entonces actualiza los registros para indicar que éstos son empleados temporales.
Para cada registro en el Recordset, el ejemplo cambia los campos Title y Notes y salva los
cambios con el método Update. Este usa el método MoveNext para moverse al registro
próximo:
Function UpdateEmployees()
Dim dbs As Database, rstEmployees As Recordset, strQuery As String
Dim intI As Integer
On Error GoTo ErrorHandler
Set dbs = CurrentDb
' Abre un Recordset con todos los registros desde la tabla Employees
' que tienen un valor Null en el camop ReportsTo.
strQuery = "SELECT * FROM Employees WHERE ReportsTo IS NULL;"
Set rstEmployees = dbs.OpenRecordset(strQuery, dbOpenDynaset)
' Si el Recordset está vacio, sale.
If rstEmployees.EOF Then Exit Function
intI = 1
With rstEmployees
Do Until .EOF
.Edit
![ReportsTo] = 5
![Title] = "Temporary"
![Notes] = rstEmployees![Notes] & "Temp #" & intI
20
Manual del Alumno
.Update
.MoveNext
intI = intI + 1
Loop
.Close
End With
ErrorHandler:
Select Case Err
Case 0
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
Cabe aclarar que este ejemplo es meramente ilustrativo, dado que el método Update
funcionaría mejor utilizando una sentencia SQL.
Detectando los límites de un objeto Recordset:
En un objeto Recordset si se intenta mover a una posición que no es la correcta, se
produce un error de ejecución. Por ejemplo, si se intenta mover al próximo registro estando
en el último o al anterior estando en el primero.
La propiedad EOF indica el fin del archivo y BOF el inicio del mismo. Se puede
acceder a estas propiedades para determinar el inicio o final del archivo y asi controlar el
movimiento del puntero. En ambos casos se pretende obtener si la propiedad es False o
True.
El siguiente ejemplo muestra como utilizar las propiedades BOF y EOF para detectar
el inicio y final de un Recordset. Este fragmento de codigo crea un Recordset de tipo table
basada en la tabla Orders. Se realizan movimientos a traves de los registros, primero desde
el inicio del Recordset hasta el final de la tabla y luego hacia el final.
Dim dbs As Database, rstOrders As Recordset
Set dbs = CurrentDb
Set rstOrders = dbs.OpenRecordset("Orders", dbOpenTable)
Do Until rstOrders.EOF
.
. ' Manipulación de los datos.
.
rstOrders.MoveNext
' Mueve el puntero al próximo registro.
Loop
rstOrders.MoveLast
' Mientras sea inicio del archivo
' Mueve el puntero al último registro.
21
Manual del Alumno
Do Until rstOrders.BOF
.
. ' Manipulación de los datos.
' Mueve el puntero al registro anterior.
rstOrders.MovePrevious
Loop
rstOrders.Close
' Cierra el Recordset.
Las propiedades BOF y EOF tienen las siguientes características:






Si el Recordset no contiene registros cuando se abre éste, tanto BOF como EOF son
True.
Cuando BOF o EOF son True, la propiedad True se mantienen hasta que exista un
movimiento hasta un registro existente, asignando False a BOF o EOF.
Cuando BOF o EOF es False, y solo el registro en el Recordset es eliminado, la
propiedad devuelve False hasta que se desplaze el puntero hasta otro registro.
En el momento en que se crea o abre un Recordset que contiene más de un registro,
el primero de ellos es el registro actual y tanto BOF y EOF son False.
Si el primer registro en el registro actual cuando use el método MovePrevious, BOF
es puesto en True. Si se utiliza MovePrevious mientras BOF es True, un error en
tiempo de ejecución ocurre.
Similarmente, moviéndose al último registro en el Recordset se cambia el valor de la
propiedad EOF a True. Si se utiliza el método MoveNext mientras EOF es True, un
error en tiempo de ejecución se presenta.
Contando el número de registros en un objeto Recordset:
Si puede conocer el número de registros en un objeto Recordset. Por ejemplo, si se
necesita crear un formulario que muestre cuantos registros existen en cada tabla de la base de
datos o los cambios presentados cuando se realizan inclusiones.
La propiedad RecordCount contiene el número de registros en un Recordset tipo tabla o
el total de registros accesados en un dynaset o snapshot. Un objeto Recordset sin registros
posee la propiedad RecordCount en 0.
El siguiente ejemplo crea un Recordset tipo snapshot y determina el número de registros
en el mismo:
Function RecCount(strSQL As String) As Long
Dim rstCount As Recordset, dbs As Database
On Error GoTo ErrorHandler
Set dbs = CurrentDb
Set rstCount = dbs.OpenRecordset(strSQL)
If rstCount.EOF Then
22
Manual del Alumno
rstCount.Close
RecCount = 0
Exit Function
Else
rstCount.MoveLast
RecCount = rstCount.RecordCount
rstCount.Close
Exit Function
End If
ErrorHandler:
Select Case Err
Case 0
Exit Function
Case Else
MsgBox "Error:" & Err & ":" & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
Cuando se eliminan registros en un Recordset tipo dynaset, el valor de RecordCount
decrece. Sin embargo, en un ambiente multiusuario, los registros eliminados por otros
usuarios no son reflejados en el valor del RecordCount hasta que el registro acutal es
posicionado sobre un registro eliminado. Al mismo tiempo la configuración de la propiedad
RecordCount es actualizada. Utilizando el método Requery sobre un Recordset, seguido
por un metodo MoveLast, configuran la propiedad RecordCount al número total de
registros en el Recordset.
Un Recordset tipo snapshot es estático y el valor RecordCount de este no se cambia
cuando se agregan o eliminan registros.
Buscando la posición actual en un objeto Recordset:
Dos propiedades están disponibles para indicar la posición actual de un registro:
AbsolutePosition y PercentPosition.
El valor de la propiedad AbsolutePosition es la posición del registro actual relativo a
0. Sin embargo, no se piense como un número de registro; si el registro actual está
indefinido, la propiedad AbsolutePosition retorna –1. En consecuencia, esto no significa
que el registro tendrá la misma posicion absoluta si el objeto Recordset es recreado, porque
el orden de los registros individuales en un Recordset utilizando SQL que incluyan la
claúsula Order By cambia dichas posiciones.
La propiedad PercentPosition muestra la posicion actual expresada como un
porcentaje del total de registros indicados en la propiedad RecordCount. Para asegurarse la
correcta asignación del porcentaje referido utilicese los metodos MoveLast y MoveFirst
antes de abrir el Recordset.
23
Manual del Alumno
La propiedad PercentPosition es solamente una aproximacion y no debería ser
utilizada como un parametro critico. Esta propiedad es mejor para manejar un indicador que
marque el progreso en una operación de registros procesados.
El siguiente ejemplo abre un objeto Recordset en una tabla llamada Employees. El
procedimiento entonces permite moverse a traves de la tabla y usa la funcion SysCmd para
desplegar una barra de progreso, mostrando el porcentaje que ha sido procesada en la tabla.
Si la fecha de nacimiento del empleado es posterior al 1 Enero de 1993, el texto “Senior
Staff” es agregado al campo Notes.
Function PercentPos()
Dim dbs As Database, strMsg As String, rstEmployees As Recordset, intRet%
Dim intCount As Integer, strQuery As String, sngPercent As Single
Dim varReturn As Variant
Dim lngEmpID() As Long
On Error GoTo ErrorHandler
strQuery = "SELECT * FROM Employees;"
Set dbs = CurrentDb
Set rstEmployees = dbs.OpenRecordset(strQuery, dbOpenDynaset)
With rstEmployees
If .EOF Then
' Si no hay registros, sale.
Exit Function
Else
strMsg = "Procesando tabla Employees ..."
intRet = SysCmd(acSysCmdInitMeter, strMsg, 100)
End If
Do Until .EOF
If !HireDate < #1/1/93# Then
.Edit
!Notes = !Notes & ";" & "Senior Staff"
.Update
End If
If .PercentPosition <> 0 Then
intRet = SysCmd(acSysCmdUpdateMeter, .PercentPosition)
End If
.MoveNext
Loop
.Close
End With
intRet = SysCmd(acSysCmdRemoveMeter)
ErrorHandler:
Select Case Err
Case 0
24
Manual del Alumno
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
' limpia la métrica de progreso.
varReturn = SysCmd(acSysCmdSetStatus, " ")
Exit Function
End Select
End Function
Buscando un registro específico:
Muchas veces se desea encontrar un registro particular de un empleado, por ejemplo,
basados en el código del mismo, o todos los detalles que se especifican para una determinada
orden. En estos casos, se puede realizar una búsqueda utilizando los métodos Find y Seek.
Se puede utilizar el metodo Seek con tipos de Recordset Tables y el método Find con
dynaset y snapshot. Forward-Only no soporta el uso de Seek o cualquiera de los Find.
Buscando un registro en un Recordset tipo Table:
Se puede utilizar el metodo Seek para localizar registros en un Recordset tipo Table.
Cuando se usa el método Seek para localizar un registro, el motor de base de datos
Microsoft Jet usa los indices de la tabla, definidas por la propiedad Index.
Si se utiliza el método Seek en un Recordset tipo table, sin haber habilitado el indice
primero, ocurre un error en tiempo de ejecucion.
La sintaxis para el método Seek es el siguiente:
table.Seek comparison, key1, key2 ...
El argumento table es el Recordset tipo table utilizado.
El argumento comparación es una cadena que determina la clase de comparacion que
esta siendo aplicada. La siguiente tabla lista las cadenas de comparacion que se pueden
utilizar con el método Seek.
Cadena de comparación
Description
"="
">="
">"
"<="
"<"
Igual al valor especificado
Mayor o igual al valor especificado
Mayor al valor especificado
Menor o igual al valor especificado
Menor al valor especificado
25
Manual del Alumno
El argumento Keyn son una serie de uno o más valores que corresponden al campo o
campos que inicializan el indice actual del Recordset. Microsoft Jet compara estos valores
con los valores en los campos correspondientes del Recordset.
El ejemplo siguiente abre un Recordset tipo table llamada Employees y utiliza el
metodo Seek para localizar el record conteniendo el valor de IngEmpID en el campo
EmployeeID. Este returna la fecha de nacimiento del empleado referido:
Function intGetHireDate(lngEmpID As Long, varHireDate As Variant) As Integer
Dim rstEmployees As Recordset, dbs As Database
Const conFilePath$ = "C:\Program Files\Microsoft _ Office\Office\Samples\"
On Error GoTo ErrorHandler
Set dbs = OpenDatabase(conFilePath & "Northwind")
Set rstEmployees = dbs.OpenRecordset("Employees", dbOpenTable)
rstEmployees.Index = "PrimaryKey" 'Nombre del indice para Employee ID.
rstEmployees.Seek "=", lngEmpID
If rstEmployees.NoMatch Then
varHireDate = Null
'La constante conErrNoMatch, conSuccess, y conFailed están definidos
'en el nivel de módulo como una constante publica con valores enteros
'entre -32,761, 0, y -32,737 respectivamente.
intGetHireDate = conErrNoMatch
Exit Function
Else
varHireDate = rstEmployees!HireDate
intGetHireDate = conSuccess
Exit Function
End If
ErrorHandler:
Select Case Err
Case 0
Exit Function
Case Else
varHireDate = Null
intGetHireDate = conFailed
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
El metodo Seek siempre inicia buscando registros desde el principio del Recordset.
Se puede utilizar la propiedad NoMatch en el Recordset para comprobar si el registro
buscado no fue encontrado, mediante examinación del valor True o False.
El siguiente ejemplo ilustra como se puede crear una función que utilice el método
Seek para localizar un registro utilizando un indice de multiples campos:
Function GetFirstPrice(lngOrderID As Long, lngProductID As Long) As Variant
Dim dbs As Database, rstOrderDetail As Recordset
26
Manual del Alumno
On Error GoTo ErrorHandler
Set dbs = CurrentDb
Set rstOrderDetail = dbs.OpenRecordset("Order Details", dbOpenTable)
rstOrderDetail.Index = "PrimaryKey"
rstOrderDetail.Seek "=", lngOrderID, lngProductID
If rstOrderDetail.NoMatch Then
GetFirstPrice = Null
MsgBox "No se encontró el registro..."
Else
GetFirstPrice = rstOrderDetail!UnitPrice
End If
rstOrderDetail.Close
ErrorHandler:
Select Case Err
Case 0
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
En este ejemplo, la llave primaria de la tabla consiste en dos campos: OrderID y
ProductID. Cuando llama a la función GetFirstPrice con una combinación válida de campos
para OrderID y ProductID, la función retorna el precio unitario desde el registro encontrado.
Si no se encuentra la combinación de valores de campo la función retorna un valor Null.
Buscando un registro en tipos de Recordset Dynaset- o Snapshot:
Se puede utilizar el método Find para localizar un registro en un Recordset tipo
Dynaset o Snapshot. DAO provee cuatro metodos para lo anterior:




FindFirst : busca el primer registro que satisface el criterio de búsqueda.
FindLast : busca el último registro que satisface el criterio de búsqueda.
FindNext: busca el próximo que satisface el criterio de búsqueda.
FindPrevious : busca el registro que satisface el criterio de búsqueda.
Nota: Para localizar un registro en un Recordset tipo table, debe utilizarse el método
Seek, descrito anteriormente.
Cuando se utilice el metodo Find desde especificarse el criterio de busqueda;
tipicamente es una expresion con un nombre de campo con un valor especifico.
Se pueden localizar los registros buscados en orden último, anterior o siguiente,
utilizando los métodos FindLast, FindPrevious y FindNext.
27
Manual del Alumno
DAO almacena True en la propiedad NoMatch cuando un metodo Find falla y el
registro actual yace indefinido. Para retornar al registro actual debe utilizarse el metodo
bookmark.
El ejemplo siguiente muestra como se puede utilizar el método FindNext para
encontrar todas las ordenes en la tabla Orders que tiene los registros que no corresponden en
la tabla Order Details y agrega los valores en el campo OrderID al arreglo IngOrderID():
Function FindEx(lngOrderID() As Long)
Dim dbs As Database, rstOrders As Recordset
Dim strQuery As String, rstOrderDetails As Recordset
Dim intIndex As Integer
On Error GoTo ErrorHandler
Set dbs = CurrentDb
'Abre un recordset con los registros de las tablas
'orders y Order Details.
'Si éstas no contienen registros sale.
strQuery = "SELECT * FROM Orders ORDER BY OrderID;"
Set rstOrders = dbs.OpenRecordset(strQuery, dbOpenSnapshot)
If rstOrders.EOF Then Exit Function
strQuery = "SELECT * FROM [Order Details] ORDER BY OrderID;"
Set rstOrderDetails = dbs.OpenRecordset(strQuery, dbOpenSnapshot)
' Para el primer registro en Orders, encuentra el primer registro.
' en OrderDetails. Si no no encuentra, redimensiona el arreglo de order IDs
' y agrega el order ID al arreglo.
rstOrderDetails.FindFirst "OrderID = " & rstOrders![OrderID]
If rstOrderDetails.NoMatch Then
ReDim Preserve lngOrderID(1 To intIndex)
lngOrderID(intIndex) = rstOrders![OrderID]
End If
' La primera búsqueda ha sido exitosa, entonces usa FindNext para encontrar
' próximo registro que satisfaga el criterio de búsqueda.
intIndex = 0
Do Until rstOrders.EOF
rstOrderDetails.FindNext "OrderID = " & rstOrders![OrderID]
If rstOrderDetails.NoMatch Then
intIndex = intIndex + 1
ReDim Preserve lngOrderID(1 To intIndex)
lngOrderID(intIndex) = rstOrders![OrderID]
End If
rstOrders.MoveNext
Loop
ErrorHandler:
Select Case Err
Case 0
Exit Function
28
Manual del Alumno
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
Si la búsqueda de registros es frecuente en un Recordset tipo dynaset, se pueden
encontrar éstos facilmente creando una tabla indexada temporal y usar el método Seek.
Marcando la posición de un registro con Bookmarks:
Un bookmark es un sistema generado que identifica univocamente a cada registro. La
propiedad bookmark de DAO en un Recordset cambia cada vez que se mueve a un nuevo
registro. Para identificar un registro, se marca el registro actual con Bookmark en una
variable tipo Variant. Para retornar a éste registro, asignele al bookmark el valor de esta
variable.
El siguiente ejemplo ilustra como se puede usar bookmark para salvar la posicion
actual del registro. Se pueden realizar otras operaciones sobre el recordset y posteriormente
regresar al registro marcado.
Function BookMarkEx() As Integer
Dim dbs As Database, rstProducts As Recordset
Dim vBookMark As Variant, sngRevenue As Single
Dim strQuery As String, rstCategories As Recordset, strCriteria As String
On Error GoTo ErrHandler
BookMarkEx = 0
strQuery = "SELECT * FROM Products WHERE UnitsOnOrder >= 40 _
ORDER BY " _
& "CategoryID, UnitsOnOrder DESC;"
Set dbs = CurrentDb
Set rstProducts = dbs.OpenRecordset(strQuery, dbOpenSnapshot)
Set rstCategories = dbs.OpenRecordset("SELECT CategoryID FROM " _
& "Categories ORDER BY CategoryID;", dbOpenSnapshot)
If rstProducts.NoMatch Then Exit Function
' Por cada categoría encontrada el producto genera el ingreso mínimo
' y el producto de mayor precio.
Do Until rstCategories.EOF
strCriteria = "CategoryID = " & rstCategories![CategoryID]
rstProducts.FindFirst strCriteria
sngRevenue = rstProducts![UnitPrice] * rstProducts![UnitsOnOrder]
If Not rstProducts.NoMatch Then
'Inicializa el bookmark en el primer registro conteniendo la
29
Manual del Alumno
'CategoryID.
vBookMark = rstProducts.Bookmark
'Buscar el producto generando el de mayor precio
Do While rstProducts![CategoryID] = rstCategories![CategoryID]
If rstProducts![UnitPrice] * rstProducts![UnitsOnOrder] > sngRevenue Then
sngRevenue = rstProducts![UnitPrice] * _
rstProducts![UnitsOnOrder]
End If
rstProducts.MoveNext
Loop
' Se mueve al primer registro que contiene el campo CategoryID.
rstProducts.Bookmark = vBookMark
sngRevenue = rstProducts![UnitPrice] * _
rstProducts![UnitsOnOrder]
' Encuentra el producto, generando el de menor precio/ingreso.
Do While rstProducts![CategoryID] = rstCategories![CategoryID]
If rstProducts![UnitPrice] * rstProducts![UnitsOnOrder] < sngRevenue Then
sngRevenue = rstProducts![UnitPrice] * rstProducts![UnitsOnOrder]
End If
rstProducts.MoveNext
Loop
End If
rstCategories.MoveNext
Loop
' Error Handler.
ErrHandler:
Select Case Err
Case 0
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
Un “bookmark” es particularmente útil si un método falla, por que la posición actual
del registro se pierde.
La propiedad LastModified del objeto Recordset clarifica el como usar el bookmark.
Esta propiedad retorna el bookmark del ultimo registro en el Recordset a ser añadido o
modificado. Para usar este, se debe configurar la propiedad Bookmark de DAO para que
sea igual a la propiedad LastModified, tal y como se muestra a continuación:
RstClientes.BookMark = rstClientes.LastModified
30
Manual del Alumno
Lo anterior mueve el registro actual hasta el último que fue agregado o modificado.
Esto es particularmente útil cuando se agregan nuevos registros, por que después de hacerlo
el registro actual es el que se añadió. Con la propiedad LastModified, se puede mover al
registro recién agregado.
Cuando usted cierra un objeto Recordset, cualquier bookmarks que haya salvado se
invalida. No se puede usar un bookmark de un Recordset en otro. Sin embargo, puede
usarse como en el siguiente ejemplo:
Dim dbs As Database
Dim rstOriginal As Recordset, rstDuplicate As Recordset
Dim strPlaceholder As String
Set dbs = CurrentDb
' Crea el primer Recordset.
Set rstOriginal = dbs.OpenRecordset("Orders", dbOpenDynaset)
' Guarda la posición del registro actual
strPlaceholder = rstOriginal.Bookmark
' Crea un Recordset duplicado.
Set rstDuplicate = rstOriginal.Clone()
' Se desplaza al mismo registro.
rstDuplicate.Bookmark = strPlaceholder
rstOriginal.Close
Que objetos Recordset no soportan Bookmarks?
Los Recordset de tipo Dynaset basados en ciertas tablas ligadas, como tablas Paradox
que no tienen llaves primarias no soportan bookmarks. Se puede determinar si un objeto
Recordset soporta o no bookmarks chequeando el valor de la propiedad bookmarkable, tal y
como se muestra en el ejemplo siguiente:
If rstLinkedTable.Bookmarkable Then
MsgBox "Esta tabla soporta bookmarks."
Else
MsgBox "Esta tabla no soporta bookmarks."
End If
Cambiando datos:
Despues que se crea un Recordset tipo table o dynaset, se pueden modificar, eliminar o
agregar nuevos registros. Lo anterior no se puede realizar si el Recordset es snapshot, o
forward-only.
Usando consultas parametrizadas:
31
Manual del Alumno
Una consulta parametrizada es aquella que cuando se ejecuta despliega una caja de
diálogo que le indica al usuario que debe digitar información, como por ejemplo un criterio
para la búsqueda de registros o valores para insertar en un campo. Se pueden utilizar
procedimientos almacenados para brindar procesos de mantenimiento de bases de datos o
para recuperar consultas de uso intensivo.
Para crear un procedimiento o consulta almacenada deben realizarse los siguientes
pasos:
 Cree una consulta almacenada, especificando los parámetros que el usuario
necesita proveer.
 Cuando se abre un Recordset utilizando esta consulta, la aplicación abre una caja
de diálogo que solicita al usuario los valores para los parámetros establecidos en la
consulta.
El siguiente ejemplo toma dos cadenas que representan fechas y crea una consulta
parametrizada que retorna todos aquellos registros en la tabla Orders cuyo campo Order Date
esté entre las dos fechas. Este añade todos los valores del campo OrderId retraido en la
consulta y los almacena en un arreglo:
Function OrdersFromTo(strDateFrom As Variant, strDateTo As Variant, _
lngOrderIDs() As Long)
Dim dbs As Database, rstOrders As Recordset
Dim qdf As QueryDef, strSQL As String, intI As Integer
On Error GoTo ErrorHandler
Set dbs = CurrentDb
strSQL = "PARAMETERS [DateFrom] DateTime, [DateTo] DateTime; "
strSQL = strSQL & "SELECT * FROM Orders WHERE OrderDate BETWEEN
"
strSQL = strSQL & "[DateFrom] AND [DateTo];"
' Crea una consulta almacenada parametrizada.
Set qdf = dbs.CreateQueryDef("", strSQL)
' configura los parámetros de la consulta.
qdf.Parameters("DateFrom") = strDateFrom
qdf.Parameters("DateTo") = strDateTo
'Abre un Recordset forward-only snapshot.
Set rstOrders = qdf.OpenRecordset(dbOpenSnapshot, dbForwardOnly)
' Carga en un arreglo todos los registros del campo OrderIDs
' obtenidos en la consulta
intI = 1
While rstOrders.EOF = False
ReDim lngOrderIDs(1 To intI)
32
Manual del Alumno
lngOrderIDs(intI) = rstOrders!OrderID
intI = intI + 1
rstOrders.MoveNext
Wend
ErrorHandler:
Select Case Err
Case 0
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
Exit Function
End Select
End Function
Para más información veáse en la ayuda: “parameter queries.”
Marcando cambios Bulk:
Muchos de los cambios que se pueden realizar en una base de datos pueden
eficientizarse utilizando consultas definidas. El ejemplo siguiente crea un objeto QueryDef
para actualizar la tabla Employees:
Dim dbs As Database, qdfChangeTitles As QueryDef
Set dbs = CurrentDb
Set qdfChangeTitles = dbs.CreateQueryDef("")
qdfChangeTitles.SQL = "UPDATE Employees SET Title = 'Account Executive' " _
& "WHERE Title = 'Sales Representative';"
qdfChangeTitles.Execute dbFailOnError
' llama a la consulta.
Se puede reemplazar toda la cadena SQL en este ejmplo con una consulta almacenada
parametrizable. El siguiente ejemplo muestra como el código anterior puede ser reescrito
como una consulta almacenada y no como consulta definida:
Dim dbs As Database, qdfChangeTitles As QueryDef
Dim strSQLUpdate As String, strOld As String
Dim strNew As String
Set dbs = CurrentDb
strSQLUpdate = "PARAMETERS [Old Title] Text, [New Title] Text; " _
& "UPDATE Employees SET Title = [New Title] WHERE Title = [Old
Title];"
' Crea el objeto QueryDef.
Set qdfChangeTitles = dbs.CreateQueryDef("", strSQLUpdate)
33
Manual del Alumno
' Solicita al usuario el valor anterior.
strOld = InputBox("Digite el puesto anterior")
' Solicita al usuario el nuevo valor.
strNew = InputBox("Digite el nuevo puesto")
' Configura los parametros.
qdfChangeTitles.Parameters("Old Title") = strOld
qdfChangeTitles.Parameters("New Title") = strNew
' Invoca la consulta.
qdfChangeTitles.Execute
Nota: una consulta de eliminación en más eficiente que el código que busca ciclicamente a
través de un conjunto de registros, especialmente con bases de datos creadas con Access para
Windows 95 o superior.
Modificando un registro existente:
Se pueden modificar registros existentes en un Recordset tipo table o dynaset usando
los métodos Edit y Update.
Para modificar un registro existente en un Recordset table o dynaset:
1.
2.
3.
4.
Localizar el registro que se quiere modificar.
Use el método Edit para preparar el registro actual para edición.
Realice los cambios necesarios al registro.
Use el método Update para salvar los cambios hechos.
El siguiente ejemplo ilustra como cambiar el título del puesto para todos los
representantes de ventas contenidos en una tabla llamada Employees.
Dim dbs As Database, rstEmployees As Recordset
Set dbs = CurrentDb
Set rstEmployees = dbs.OpenRecordset("Employees")
rstEmployees.MoveFirst
Do Until rstEmployees.EOF
If rstEmployees!Title = "Sales Representative" Then
rstEmployees.Edit
rstEmployees!Title = "Account Executive"
rstEmployees.Update
End If
rstEmployees.MoveNext
34
Manual del Alumno
Loop
rstEmployees.Close
Es importante notar que si se utiliza el método Edit antes que se realicen los cambios
ocurre un error de ejecución. Si se edita el registro actual y entonces se mueve el puntero de
registros o se cierra el Recordset sin haber primeramente ejecutado un metodo Update, los
cambios realizados no surtirán efecto.
Se puede finalizar el método Edit y cualquier otra transacción pendiente sin salvar los
cambios utilizando el método CancelUpdate.
Actualizaciones inconsistentes:
Un Recordset tipo dynaset puede estar basados en una consulta de múltiples tablas con
una relación tipo uno a muchos. Por ejemp.lo, supongase que se desea crear una consulta de
múltiples tablas que combinan campos de las tablas Orders y Order Details. Generalmente
hablando no se pueden cambiar valores en la tabla Orders por que están subordinados a los
valores Order Details. Los cambios en estos casos tienen que realizarse en ámbas tablas para
que no se presenten inconsistencias. En tal caso puede utilizarse la constante dbInconsistent
del método OpenRecordset para crear un dynaset inconsistente.
Por ejemplo:
Set rstTotalSales = dbs.OpenRecordset("Sales Totals" ,, _ dbInconsistent)
Cuando se actualiza un dynaset inconsiste, se puede facilmente destruir la integridad
referencial de los datos en el dynaset. Por ende, debe procurarse realizar los cambios en
todas aquellas tablas que mantengan esta integridad referencial.
La constante dbInconsisten está disponible solo para los objetos Recordset de tipo
dynaset. Este es ignorado para los de tipo table, snapshot y forward-only.
Elimimando un registro existente:
Se puede eliminar un registro existente en un Recordset de tipo table o dynaset
utilizando el método Delete. No se pueden eliminar registros de un snapshot.
El ejemplo siguiente muestra como eliminar todos los registros duplicados en la tabla
Shippers:
Function DeleteDuplicateShippers() As Integer
Dim rstShippers As Recordset, strQuery$, dbs As Database, strName$
On Error GoTo ErrorHandler
strQuery = "SELECT * FROM Shippers ORDER BY CompanyName;"
Set dbs = CurrentDb
Set rstShippers = dbs.OpenRecordset(strQuery, dbOpenDynaset)
' Si no hay registros en la tabla Shippers table, sale.
35
Manual del Alumno
If rstShippers.EOF Then Exit Function
strName = rstShippers![CompanyName]
rstShippers.MoveNext
Do Until rstShippers.EOF
If rstShippers![CompanyName] = strName Then
rstShippers.Delete
Else
strName = rstShippers![CompanyName]
End If
rstShippers.MoveNext
Loop
ErrorHandler:
Select Case Err
Case 0
' La constante conSuccess y conFailed son definidas en
' el nivel de módulo como constante pública con valor entero.
' con valores de 0 y -32,737 respectivamente.
DeleteDuplicateShippers = conSuccess
Exit Function
Case Else
MsgBox "Error " & Err & ": " & Error, vbOKOnly, "ERROR"
DeleteDuplicateShippers = conFailed
Exit Function
End Select
End Function
Cuando se usa el metodo Delete, Microsoft Jet inmediatamente elimina el registro
actual (después de ejecutar la búsqueda, por supuesto), sin presentar ninguna advertencia al
respecto. Si se elimina el registro actual el motor no provee un desplazamiento automático al
siguiente o al registro anterior en el Recordset, por tanto debe utilizarse el método MoveNext
para realizarlo.
Si se intenta accesar un registro previamente eliminado en el Recordset tipo table se
puede presentar una condición de error: 3167 “Registro eliminado”. En un dynaset se puede
obtener el error 3021 “No registro actual”.
Agregando un nuevo registro:
Se puede agregar un nuevo registro a un Recordset tipo table o dynaset utilizando el
método AddNew.
Para agregar un nuevo registro a un Recordset table o dynaset:
1. Use el método AddNew para crear un nuevo registro.
2. Asigne valores para cada campo del registro.
3. Use el método Update para guardar los datos o CancelUpdate para cancelar.
36
Manual del Alumno
El siguiente ejemplo agrega un nuevo registro en el Recordset tipo tabla de nombre
rstShippers:
Dim dbs As Database, rstShippers As Recordset
Set dbs = CurrentDb
Set rstShippers = dbs.OpenRecordset("Shippers")
rstShippers.AddNew
rstShippers!CompanyName = "Global Parcel Service"
.
. ' Set remaining fields.
.
rstShippers.Update
rstShippers.Close
Cuando se utiliza el método AddNew, Microsoft Jet prepara un nuevo registro en
blanco y lo habilita como el registro actual. Si se añade un registro a un Recordset de tipo
dynaset este nuevo registro aparece al final del Recordset. Para forzarlo a que aparezca en la
posición adecuada de un ordenamiento se debe recrear el Recordset mediante el método
Requery. Si se agrega un registro a un Recordset tipo table, el registro aparece posicionado
de acuerdo al indice actual, o al final de la tabla si no hay un índice abierto.
Transacciones Microsoft Jet:
Una transacción es un conjunto de operaciones realizadas que son tratadas como una
sola unidad de trabajo. El trabajo en una transacción pueden ser completadas como un todo;
si una parte de la misma falla toda la transacción falla. Las transacciones ofrecen al
desarrollador de software la posibilidad para reforzar la integridad de la informacion.
Cuando múltiples tablas son involucradas en procesos de actualización, por ejemplo, pueden
surgir fallas que pueden crear inconsistencias peligrosas de información.
El ejemplo más común de transacciones son las que atañen a la automatización
bancaria de algunos procesos, Automated Teller Machine (ATM). El proceso de dispensar
dinero y el débito y crédito de cuentas son consideradas una unidad lógica de trabajo y que
son tratadas como una transacción: el dinero no puede ser dispensado sin que el sistema esté
disponible para realizar el débito de la cuenta.
Utilizando Transacciones en aplicaciones:
Microsoft Jet soporta transacciones a traves de DAO: BeginTrans, CommitTrans y
Rollback. La sintaxis básica de estos métodos se muestran en la siguiente tabla:
Método
Workspace.BeginTrans
Workspace.CommitTrans
Operación
Inicia la transacción
Después de la transacción escribe y actualiza permanente a los
objetos relacionados en la base de datos.
37
Manual del Alumno
Workspace.Rollback
Cancela las transacciones, por error o por decisión del usuario.
El siguiente ejemplo cambia los títulos de oficio de todos los representantes de ventas
en la tabla Employees de la base de datos Northwind. Después del método BeginTrans
inicia una transacción que realiza los cambios respectivos en la tabla Employees, el método
CommitTrans guarda los cambios realizados. Se puede utilizar el método Rollback para
cancelar los cambios realizados con el Update y restaurar la tabla a su estado original.
Sub ChangeTitle()
Dim dbsSales As Database
Dim rstEmp As Recordset
Dim wrkCurrent As Workspace
Set wrkCurrent = DBEngine.Workspaces(0)
Set dbsSales = OpenDatabase("Northwind.mdb")
Set rstEmp = dbsSales.OpenRecordset("Employees", dbOpenTable)
wrkCurrent.BeginTrans
Do Until rstEmp.EOF
If rstEmp!Title = "Sales Representative" Then
rstEmp.Edit
rstEmp!Title = "Sales Associate"
rstEmp.Update
End If
rstEmp.MoveNext
Loop
If MsgBox("Guarda todos los cambios?", vbQuestion + vbYesNo) = vbYes Then
wrkCurrent.CommitTrans
Else
wrkCurrent.Rollback
End If
rstEmp.Close
dbsSales.Close
End Sub
Cuando se utilizan transacciones, todas las bases de datos y los objetos Recordset en el
Workspace especificado son afectados. Esto es, las transacciones afectan al workspace
global no a una base de datos o recordset específico. Asimismo, los métodos asociados
tienen su incidencia a traves de todo el workspace: CommitTrans y Rollback.
Nota: Se pueden utilizar los métodos BeginTrans, CommitTrans y Rollback con el objeto
DBEngine. En este caso, la transacción es aplicada al workspace por defecto, como:
DBEngine.Workspaces(0).
Manejando Transacciones:
Microsoft Jet utiliza algoritmos sofisticados para proveer transacciones seguras y
confiables.
38
Manual del Alumno
Tamaño de transacciones:
El tamaño de las transacciones que se pueden realizar con Visual Basic, utilizando el
motor Jet, está limitada únicamente por la cantidad física de espacio en el disco duro en que
se realicen. Esto es, Microsoft Jet puede almacenar una cantidad de transacciones tan grande
como lo sea el medio de almacenamiento donde se realice. Si por ejemplo, en la ejecución
de una transacción se agota el espacio físico en disco se produce un error interceptable
(2004) y reacciona de acuerdo al código de la aplicación. El caso es que si la aplicación
realiza el commit después de ocurrido este error, es factible que Microsoft Jet no pueda
regenerar la base de datos por tanto no se puede determinar el número de registros afectados
(olvidemos el dbrecordaffected), poniendo a esta en un estado inconsistente. Si por el
contrario, se realiza un rollback de los cambios la base de datos queda en su estado original.
Niveles Transaccionales:
Se pueden tener hasta 5 niveles de transacciones activas al mismo tiempo. Esto es, se
pueden crear hasta 5 niveles transaccionales en una misma ejecución. Si se desea tener
transacciones con “overlapping”, “nonnested scopes” se pueden abrir objetos workspace
adicionales y manejar dichas transaccionales en dichos workspaces.
Cuando una transacción es “Rolled Back” por el motor de bases de datos Jet:
Si se cierra un objeto Workspace, cualquier transacción es automaticamente “Rolled
Back”. Microsoft Jet nunca realiza un Commit automáticamente sin haberla iniciado.
Asimismo, cuando se cierra una base de datos, variables atinentes o transacciones sin
committ sufren el mismo efecto.
Transacciones en origenes de datos externos:
Las transacciones no son soportadas en origenes de datos externas ( a excepción de
datos mediante ODBC). Por ejemplo, si la base de datos tiene ligas a tablas de FoxPro® o
dBASE®, las transacciones a estos objetos son ignorados. Para determinar o no si una base
de datos u objeto Recordset soporta transacciones se puede chequear el valor de la propiedad
Transactions. Un valor True indica que si lo soporta.
Transacciones y rendimiento:
En versiones anteriores de Microsoft Access era generalmente recomendado que se
usaran transacciones como un factor de mejoramiento en el rendimiento de aplicaciones.
Hoy día todas las transacciones para DAO (agregación, modificación y eliminación) son
mejoradas en su rendimiento internamente y automaticamente. En muchas situaciones, este
soporte automático provee a las aplicaciones el mejor rendimiento posible. Sin embargo,
muchas veces se debe recurrir a configurar algunas variables en el registro de Windows para
mejorar en este aspecto.
39
Manual del Alumno
Extrayendo Datos desde un registro:
Después de que se ha localizado un registro particular, se puede necesitar extraer datos
para usar en un aplicación, sea quiza para modificarlo.
Copiando un campo simple:
Se puede copiar un campo simple de un registro a una variable del tipo apropiado. El
ejemplo siguiente extrae tres campos del primer registro del objeto Recordset:
Dim dbs As Database, rstEmployees As Recordset
Dim strFirstName As String, strLastName As String
Dim strTitle As String
Set dbs = CurrentDb
Set rstEmployees = dbs.OpenRecordset("Employees")
rstEmployees.MoveFirst
strFirstName = rstEmployees!FirstName
strLastName = rstEmployees!LastName
strTitle = rstEmployees!Title
rstEmployees.Close
Copiando registros completos en un arreglo:
Para copiar uno o más registros completos, se puede crear un array bidimensional y
copiar los registros en él. Se incrementa el primer parámetro por cada campo y el segundo
por cada registro.
Una via rápida para hacer esto es con el método GetRows. El método GetRows retorna
un arreglo bidimensional. El primer parámetro identifica el campo y el segundo el número
de fila, tal y como se muestra en el ejemplo siguiente:
varRecords(intField, intRecord)
El siguiente ejemplo utiliza una sentencia SQL para extraer tres campos desde una tabla
llamada Employees y los coloca en un objeto Recordset. Este entonces utiliza el método
GetRows para extraer los primeros tres registros del Recordset y almacena los registros
seleccionados en un arreglo bidimensional. Imprime entonces cada registro, campo por
campo, usando los dos arreglos indexados para seleccionar campos especificos y registros.
Para aclarar este punto se ilustra como los arreglos indexados son utilizados. El
ejemplo utiliza una sentencia separada para identificar e imprimir cada campo de cada
registro. En la práctica, es mejor utilizar dos ciclos, uno en el otro, y proveer variables
enteras para los indices que navegan en ambas dimensiones del arreglo:
40
Manual del Alumno
Sub GetRowsTest()
Dim dbs As Database
Dim rstEmployees As Recordset
Dim varRecords As Variant
Dim intNumReturned As Integer
Dim intNumColumns As Integer
Dim intColumn As Integer, intRow As Integer
Set dbs = CurrentDb
Set rstEmployees = dbs.OpenRecordset("SELECT FirstName, LastName, Title" _
& " FROM Employees", dbOpenSnapshot)
varRecords = rstEmployees.GetRows(3)
intNumReturned = UBound(varRecords, 2) + 1
intNumColumns = UBound(varRecords, 1) + 1
For intRow = 0 To intNumReturned - 1
For intColumn = 0 To intNumColumns - 1
Debug.Print varRecords(intColumn, intRow)
Next intColumn
Next intRow
rstEmployees.Close
End Sub
Se puede utilizar subsecuentes llamadas al método GetRows si hay más registros
disponibles.
Usando Consultas sumarizadas:
Se puede sumarizar datos utilizando las claúsulas GROUP BY y HAVING. GROUP
BY organiza los datos dentro de grupos; HAVING configura condiciones de grupos para
incluir en el resultado. Estas claúsulas pueden estar juntas, HAVING usada sin GROUP BY
puede producir resultados confusos.
Usando Eventos del Control Data:
Tres eventos se pueden utilizar en aplicaciones de bases de datos, utilizando Visual
Basic: Validate, Error y Reposition.
Evento Validate:
Este evento se utiliza para comprobar los datos del RecordSet antes de guardar el
registro en la base de datos. Este evento se produce antes de que Visual Basic escriba los
datos en la base de datos. Es útil para solicitar al usuario confirme los cambios a realizar en
la base de datos.
La sintaxis de este evento es la siguiente:
Private Sub Data1_Validate (index As Integer, action As Integer, save As Integer)
El argumento action indica la operación que provocó el evento Validate. Este evento
es producto de realizar las siguientes operaciones: MoveFirst, MovePrevious, MoveNext,
41
Manual del Alumno
MoveLast, AddNew, Update, Delete, Find, establecer la propiedad BookMark, cerrar la
base de datos, descargar el formulario. Para cancelar cualquiera de estas acciones, se debe
asignarsele vbDataActionCancel al argumento action.
El argumento save indica si va a guardarse o no el registro. Si save es True, los datos
enlazados han cambiado. Para cancelar la acción de guardar puede asignarse False al
argumento save.
El código siguiente solicita al usuario que confirme los cambios realizados en la base
de datos. Si el usuario indica que no, los cambios se cancelarán automáticamente:
Private Sub Data1_Validate (Action As Integer, Save As Integer)
Dim Respuesta As Integer
If Save = True Then
Respuesta = MsgBox ("¿Guardar cambios?", vbYesNo)
If Respuesta = vbNo Then
Save = False
Data1.UpdateControls ' Actualiza campos.
End If
End If
End Sub
Evento Reposition:
El evento Reposition se utiliza para modificar la apariencia de un formulario o realizar
una acción necesaria cuando se desplace a un nuevo registro. Esto se realiza cuando Visual
Basic se desplaza a otro registro o cuando se abre la base de datos.
Se puede variar la apariencia de un formulario mostrando información sobre cuántos
registros se encuentran en el Recordset activo. Para ello, debe utilizarse la propiedad
AbsolutePosition. El código siguiente ilustra como demostrar lo anterior:
Private Sub Data1_Reposition()
Data1.Caption = "Número de registro " & _
Data1.Recordset.AbsolutePosition + 1
End Sub
Evento Error:
Este evento se ejecuta cuanto el usuario interactua con el control data y se produce un
error de acceso a datos. En este caso debe agregarse una rutina personalizada de tratamiento
de errores.
Los valores contenidos en objetos enlazados a datos no cambian cuando se produce un
error. Puede asignar el valor 0 al argumento Response para que no se muestre el mensaje de
error. El siguiente ejemplo muestra lo anterior:
42
Manual del Alumno
Private Sub Data1_Error(DataErr As Integer, Response As Integer)
If DataErr = 3022 Then 'Error de clave duplicada
MsgBox "Escriba un número de Id. de empleado único"
txtEmpID.SetFocus
Response = 0
Else
Response = 1 'muestra el mensaje de error estándar
End If
End Sub
Enlazando datos a Controles ActiveX:
Un control ActiveX es un objeto que permite interactuar a un usuario con una
aplicación. Estos objetos tienen eventos que se pueden utilizar. La extensión de estos
objetos ActiveX es .OCX.
Un ejemplo clásico, y muy utilizado, es el objeto Cuadrícula (DbGrid). Este objeto
permite mostrar datos de una base de datos en forma de cuadrícula, con lo que le permite al
usuario manipular varios registros a la vez. Este control posee la propiedad DataSource que
permite guardar el nombre del origen de datos desde el cual se cargarán sus celdas. El
DBGrid permite ver y modificar registros simultáneamente.
Se puede utilizar la colección columns para recuperar el texto de la celda seleccionada
actualmente en tiempo de ejecución mediante el siguiente código:
MsgBox DBGrid1.Columns(DBGrid1.Col).Text
Para modificar la información cargada en el DBGrid del objeto Recordset asociado
puede utilizarse el siguiente código:
Data1.Recordset.Edit
Data1.Recordset.Fields("Campeon") = "L.D.A."
Data1.Recordset.Update
El evento BeforeUpdate se ejecuta antes de que se muevan los datos desde un DBGrid
al control data. En este caso puede validarse la información respectiva y cancelarse si es
necesario.
Un objeto que tiene similares particularidades al DBGrid es el MSFlexGrid. Sin
embargo, este control solo permite datos de captura. Puede almacenar en el datos
provenientes de un data control o de una consulta mediante SQL. Muchas veces es necesario
combinar celdas, tal y como se realiza en Excel. MSFlexGrid permite realizar esto
asignando a la propiedad MergeCells un valor distinto de cero y posteriormente asignar las
propiedades de matrices MergeRow() y MergeCol() el valor True para las filas que se
deseen combinar. El siguiente ejemplo muestra como combinar las celdas de la tabla
Facturas:
43
Manual del Alumno
Private Sub Form_Load()
MSFlexGrid1.MergeCells = flexMergeFree
MSFlexGrid1.MergeCol(1) = True
End Sub
Un control de cuadro de lista enlazado a datos (DBList) o el cuador combinado
enlazado a datos (DBCombo) se utilizan para presentar un listado de datos de un Recordset.
Esto es útil cuando se desea validar datos por parte del usuario. Por ejemplo, si se desea
enviar una notificación a un cliente, se puede utilizar un control DBList para presentar la
lista de todos los nombres de clientes válidos y obtener asi su ID.
En un DBCombo para asignar datos debe configurarse la propiedad RowSource con el
nombre de un control data existente y en la propiedad ListField el nombre de un campo.
Si se debe actualizar un campo de la base de datos debe establecerse las propiedades
DataSource y DataField con lo requerido. Para establecer la relación entre la tabla que
contiene los valores de búsqueda y la tabla que se está modificando realmente, debe
establecerse la propiedad BoundColumn.
DBEngine y WorkSpace:
DAO es una metodología de acceso a datos que permite la manipulación de estos
mediante la utilización de objetos que pertenecen a su jerarquía. Sin embargo, para poder
accesar datos de una base, debe utilizarse primero el objeto DBEngine para abrir un
espacio de trabajo, o sesión, denominado Workspace.
El objeto DBEngine es el objeto de nivel superior dentro del modelo DAO. En este
contexto se pueden utilizar los métodos RepairDatabase y CompactDataBase de este
objeto para darle mantenimiento a una base de datos, tal y como se muestra en el código
siguiente:
MsgBox "El número de versión de DAO es " & _
DBEngine.Version
DBEngine.RepairDatabase "C:\MIBD.MDB"
El objeto WorkSpace define una sesión de usuario, determinando cuanto interactua su
aplicación con los datos de la base de datos. Si se abre una base de datos sin definir el
Workspace se utiliza DBEngine.Workspaces(0) como valor predeterminado para la sesión.
En el ejemplo siguiente se crea una sesión de usuario que utiliza el motor de bases de datos
de Microsoft Jet:
Dim wspNew as Workspace
Set wspNew = DBEngine.CreateWorkspace _
("NewJetWorkspace", "Admin", "", dbUseJet)
Usando el método OpenDatabase:
44
Manual del Alumno
Con este método se puede crear un objeto tipo Database. Este método se caracteriza
por manejar las siguientes tareas: el nombre de la base de datos origen, el metodo de acceso
a datos, indicación del ambiente de uso (monousuario, multiusuario), indicacion de
lectura/escritura en la base de datos o alguno de ellos, conexión ISAM, DAO u ODBC.
La sintaxis de esta función es la siguiente:
Set basededatos = espaciodetrabajo.OpenDatabase
opciones, sólolectura, conexión)
(nombrebasededatos,
La sintaxis del método OpenDatabase consta de las siguientes partes:
Argumento
basededatos
espaciodetrabajo
nombrebasededatos
Argumento
opciones
sólolectura
conexión
Descripción
Una variable de objeto que representa el objeto
Database que va a abrir.
Opcional. Una variable de objeto que representa el
objeto Workspace existente que contendrá la base de
datos. Si no incluye un valor para espaciodetrabajo,
OpenDatabase utiliza el espacio de trabajo
predeterminado.
Un tipo de datos String que es el nombre de un archivo
de base de datos Microsoft Jet existente o el nombre del
origen de datos (DSN) de un origen de datos ODBC
existente. Consulte la propiedad Name para obtener más
información acerca de este valor.
Descripción
Opcional. Un tipo de datos Variant que establece varias
opciones para la base de datos, como se especifica en
Valores.
Opcional. Un valor de tipo de datos Variant (subtipo
Boolean) que es True si desea abrir la base de datos con
acceso de sólo lectura o False (predeterminado) si desea
abrir la base de datos con acceso de lectura/escritura.
Opcional. Un tipo de datos Variant (subtipo String) que
especifica información variada sobre la conexión,
incluyendo las contraseñas.
Valores:
Para los espacios de trabajo Microsoft Jet, puede utilizar los siguientes valores para el
argumento opciones:
Valor
True
False
Descripción
Abre la base de datos en modo exclusivo.
(Predeterminado) Abre la base de datos en modo compartido.
Para los espacios de trabajo ODBCDirect, el argumento opciones determina si y
cuando informar al usuario acerca de establecer la conexión. Puede utilizar una de
las siguientes constantes:
45
Manual del Alumno
Constante
dbDriverNoPrompt
DbDriverPrompt
DbDriverComplete
Constante
DbDriverCompleteRequired
Descripción
El Administrador del controlador de ODBC utiliza la
cadena de conexión suministrada en nombrebasededatos
y conexión. Si no proporciona información suficiente,
se produce un error en tiempo de ejecución.
El Administrador del controlador de ODBC muestra
el cuadro de diálogo ODBC Data Sources, que
muestra cualquier información interesante
suministrada en nombrebasededatos o conexión. La
cadena de conexión se realiza con el DSN que el
usuario selecciona en los cuadros de diálogo o, si el
usuario no especifica un DSN, se utiliza el valor
predeterminado de DSN.
(Predeterminado) Si los argumentos conexión y
nombrebasededatos incluyen toda la información
necesaria para completar la conexión, el Administrador
del controlador de ODBC utiliza la cadena en conexión.
De otro modo funciona como cuando especifica
dbDriverPrompt.
Descripción
Esta opción funciona como dbDriverComplete
excepto que el controlador ODBC desactiva el
envío de información que no necesita para
completar la conexión.
Abriendo tablas ISAM:
Muchas veces se necesita abrir tablas o archivos que son tipo DBF, por ejemplo. En
este caso se puede utilizar la siguiente sintaxis:
Set dbMydb = OpenDatabase("\\PlaniVB", False, False, "Dbase III;")
Set rs = dbMydb.OpenRecordset("Planilla", dbOpenTable)
rs.Index = "Cedula"
Se puede observar que PlaniVB es el directorio donde está contenida la tabla que se
desea abrir. Puede observarse que el comando OpenDatabase no abre ninguna base de datos
sino que solo referencia el directorio en donde yace la tabla DBF. Seguidamente, se crea un
Recordset, de tipo Table, para abrir la tabla DBF respectiva. En la tercera línea puede
observarse como habilitar un índice “Cedula” que utiliza la tabla y que podemos utilizar en el
Recordset para realizar una búsqueda indizada en la misma, tal y como se muestra en el
código siguiente:
rs.Seek "=", Busc
Busc en este caso, es una variable que contiene el valor obtenido, por ejemplo, de un
TextBox o de cualquier objeto.
El índice puede crearse utilizando Visual Data de Visual Basic. Se abre la tabla y se
modifica mediante la apertura en modo diseño y se crea el índice que se necesita. Visual
Basic mantiene posteriormente el índice actualizado automaticamente. También puede
46
Manual del Alumno
crearse inicialmente un archivo tipo texto, con cualquier editor y salvarlo con extensión INF.
El
archivo
debe
ser
tal
y
como
se
muestra:
Archivo INDCED.INF:
NDX = CEDULA.NDX
Comentarios:
Cuando abre una base de datos, automáticamente se agrega a la colección Databases.
Además, en un espacio de trabajo ODBCDirect, el objeto Connection correspondiente al
objeto Database nuevo también se crea y anexa a la colección Connections del mismo objeto
Workspace.
Estas son algunas
nombrebasededatos:
consideraciones
que
se
debe
aplicar
cuando
utilice

Si se hace referencia a una base de datos que ya está abierta para acceso en
modo exclusivo por otro usuario, se produce un error.
 Si no se hace referencia a una base de datos existente o a un nombre de un origen de
datos ODBC válido, se produce un error.
 Si es una cadena de longitud cero ("") y conexión es "ODBC;", se muestra un cuadro
de diálogo que enumera todos los nombres de orígenes de datos ODBC registrados
para que el usuario pueda seleccionar una base de datos.
 Si se está abriendo una base de datos mediante un espacio de trabajo ODBCDirect y
proporciona el DSN en conexión, puede establecer nombrebasededatos a una
cadena de su elección que puede utilizar para hacer referencia a esta base de datos
en el código más adelante.
El argumento conexión se expresa en dos partes: el tipo de base de datos, seguido por
punto y coma (;) y los argumentos opcionales. Primero debe proporcionar el tipo de base de
datos, como "ODBC;" o "FoxPro 2.5;". A continuación, os argumentos opcionales sin un
orden concreto, separados por punto y coma. Uno de los parámetros puede ser la contraseña
(si hay alguna asignada). Por ejemplo:
"FoxPro 2.5; pwd=micontraseña"
Utilizar el método NewPassword en un objeto Database distinto de una base de datos
de ODBCDirect cambia el parámetro de contraseña que aparece en la parte ";pwd=..." de este
argumento. Debe aplicar los argumentos opciones y sólolectura
para proporcionar una cadena de origen. Consulte la propiedad Connect para su
sintaxis.
Para cerrar una base de datos y, de este modo, quitar el objeto Database de la colección
Databases, utilice el método Close en el objeto .
47
Manual del Alumno
Nota Cuando tiene acceso a un origen de datos ODBC conectado a Microsoft Jet,
puede mejorar el rendimiento de sus aplicaciones abriendo un objeto Database conectado al
origen de datos ODBC, en vez de vincular objetos TableDef individuales a tablas específicas
en el origen de datos ODBC.
El cuadro siguiente muestra el soporta que brinda Visual Basic a varios formatos de
bases de datos:
Database Format
DataBaseName
Microsoft Access
drive:\path\file.mdb
Betrieve
drive:\path\file.ddf
DBase III
drive:\path
Dbase IV
drive:\path
FoxPro Versión 2.5
drive:\path
ODBC (SQL Server,Oracle) Registered data source
Name(usualmente el
Nombre del servidor)
Connect
(none)
“Betrieve”
“dBASE III”
“DBASE IV”
“FoxPro 2.5”
“Odbc;Dsn=Server;
Uid=User; Pd = Password”
Desarrollo Avanzado de Bases de Datos:
Exigencia de la Integridad de los datos:
Este apartado no se refiere al manejo de datos con sistemas administradores de bases
de datos de alto nivel como Oracle, Sybase o Microsoft SQL Server, dado que sobrepasan el
alcance de este manual. Se refiere, por el contrario, a la manipulación de datos con
Microsoft Access o Microsoft Jet como motor de administración de datos para aplicaciones
de mediana complejidad y de uso de escritorio y no cliente servidor.
Cuando se crea una aplicación de base de datos, debe asegurarse de que sólo se
escriban datos válidos en la misma.
Microsoft Access permite crear reglas y establecer restricciones de integridad
referencial en una base de datos para ayudar a garantizar la integridad de los datos.
Se recibirá un error de tiempo de ejecución si se trata de infringir estas restricciones.
En este caso debe proporcionarse el código que intercepta estos errores y que permite al
usuario corregir los datos y continuar.
Cuando se utiliza una base de datos de Microsoft Jet, pueden definirse reglas que
especifiquen los datos que son válidos en un campo o en una tabla. Estas reglas se almacenan
con la base de datos y se exigirán independientemente de cómo modifique los datos. Por
ejemplo puede establecerse que en una tabla determinada de una base de datos no permita
valores nulos o ceros.
Propiedades de las reglas:
Con Visual Basic se pueden crear o ver las reglas de una base de datos. Los objetos
Field y Recordset cuentan con dos propiedades relacionadas con las reglas.
Estas propiedades sólo se admiten en las bases de datos de Microsoft Jet:
48
Manual del Alumno
 ValidationRule: Define los criterios de la regla.
 ValidationText : Proporciona un mensaje de error que puede mostrarse si se infringe
la regla.
Por ejemplo, si una tabla denominada Pedidos posee un campo Cantidad, puede
escribirse código que permita mostrar las propiedades Validadtion Rule y Validation Text,
tal como sigue:
Sub DisplayRule()
Set rstOrders = dbMydb.OpenRecordset("Detalles de pedidos")
' Imprime ">0"
Debug.Print rstOrders("Cantidad").ValidationRule
' Imprime "La cantidad debe ser mayor que 0"
Debug.Print rstOrders("Cantidad").ValidationText
End Sub
Nota Se puede establecer la propiedad ValidationRule de un objeto Field para definir
una regla de forma programada. Sin embargo, aquí no se explica cómo definir una regla por
programa. Para obtener más información acerca de la creación de reglas, vea la propiedad
ValidationRule en la Ayuda de Visual Basic.
Errores de infracción de las reglas:
Si cuando se actualiza un registro se infringe una regla, se producirá un error de tiempo
de ejecución. La propiedad ValidateOnSet determina cuándo se produce el error de
infracción de la regla.
Si ValidateOnSet es True, el error de tiempo de ejecución se produce cuando se
establece el campo, como se muestra en el ejemplo siguiente:
recOrders.Edit
recOrders("Cantidad").ValidateOnSet = True
recOrders("Cantidad").Value = 0 'SE GENERA UN ERROR
recOrders.Update
Si ValidateOnSet es False, el error de tiempo de ejecución se producirá cuando se
ejecute el método Update, como en el siguiente ejemplo:
recOrders.Edit
recOrders("Cantidad").ValidateOnSet = False
recOrders("Cantidad").Value = 0
recOrders.Update 'Se genera un error.
Tratamiento de las infracciones de las reglas:
Normalmente, si se produce una infracción de las reglas se deseará permitir al usuario
corregir los datos y tratar de volver a actualizarlos.
49
Manual del Alumno
Si se utiliza el control Data e infringe una regla, se producirá el evento Error. El
control Data muestra la propiedad ValidationText y cancela la actualización. El usuario
puede modificar los datos y hacer clic en el control Data para tratar de volver a realizar la
actualización.
Se puede agregar código al evento Error para realizar una acción distinta cuando se
produzca el error. Por ejemplo, puede mostrarse texto en un título en lugar de un cuadro de
mensajes o bien cambiar la propiedad ForeColor de los campos para indicar que se ha
producido un error.
Si se utilizan Objetos de acceso a datos (DAO) e infringe una regla, se recibirá un error
de tiempo de ejecución. Debe interceptarse este error e informar al usuario.
El siguiente fragmento de código muestra como desplegar un mensaje cuando se
produzca una infracción a la regla (cantidad igual a cero, por ejemplo):
Private Sub cmdUpdate_Click()
On Error GoTo update_err
rs.Edit
rs("Cantidad") = txtQuantity.Text
rs.Update
Exit Sub
update_err:
If Err.Number = 3316 Then 'determina la infracción
lblError.Caption= Err.Description
rs.CancelUpdate
Exit Sub
End If
End Sub
La propiedad Description del objeto Err contiene el valor de la propiedad
ValidationText.
Puede utilizarse el método CancelUpdate para cancelar el método Edit o AddNew
actual y para actualizar el registro actual. Pueden dejarse los datos del usuario en el
formulario o bien actualizar el formulario con los datos actuales de la base de datos.
Reglas de Integridad Referencial:
La integridad referencial hace referencia a las restricciones que se deben poner en una
base de datos para mantener las relaciones definidas entre dos tablas cuando se agregan,
cambian o eliminan registros.
Definir las restricciones de integridad referencial:
El motor de base de datos Microsoft Jet puede exigir automáticamente la integridad
referencial en las bases de datos de Microsoft Jet.
50
Manual del Alumno
Por ejemplo, puede existir una tabla denominada Clientes y otra Pedidos. No se
pueden incluir pedidos si no existe un cliente; eso es mantener la integridad referencial de los
datos.
Nota Pueden definirse las relaciones entre tablas mediante programación con Visual
Basic o bien manualmente, mediante Microsoft Access. Para obtener información acerca de
la creación de relaciones mediante programación, vea el método CreateRelation en la
Ayuda de Visual Basic.
Actualizaciones y eliminaciones en cascada:
Una vez establecida la integridad referencial, pueden especificarse las opciones
Actualizar en cascada los campos relacionados o Eliminar en cascada los registros
relacionados. Si establece estas opciones, el motor de base de datos Microsoft Jet permitirá
al usuario cambiar y eliminar registros, y cambiará o eliminará automáticamente los registros
relacionados de las tablas relacionadas.
Por ejemplo, suponga que se ha creado una relación entre las tablas Clientes y Pedidos.
Si se selecciona la opción Eliminar en cascada los registros relacionados para la tabla
Clientes, cada vez que el usuario elimine el registro de un cliente, el motor de base de datos
Microsoft Jet eliminará automáticamente todos los registros relacionados con ese cliente de
la tabla Pedidos.
Nota El motor de base de datos Microsoft Jet no muestra ninguna advertencia cuando
elimina los registros relacionados. Es muy importante que se entienda cómo están definidas
las relaciones en la base de datos para evitar pérdidas de datos al eliminar registros.
Tratamiento de las infracciones de integridad referencial:
Si se trata de infringir las restricciones de integridad referencial, se recibirá un error de
tiempo de ejecución. Debe interceptarse este error e informar al usuario.
El siguiente fragmento de código muestra un mensaje de error si el usuario intenta
eliminar el registro de un cliente que tiene un pedido:
Private Sub cmdDelete_Click()
On Error GoTo del_err
rs.Delete
rs.MoveNext
FillFields 'procedimiento escrito por el usuario
Exit Sub
del_err:
'Referencia a la violación de integridad
If Err.Number = 3200 Then
lblError.Caption = "No se puede borrar un cliente con órdenes."
Exit Sub
Else
'controlar otros errores...
51
Manual del Alumno
End If
End Sub
El registro no se elimina y no se vuelve a posicionar en el registro actual. Los cuadros
de texto del formulario siguen conteniendo los datos actuales.
Prevenir infracciones de integridad referencial:
Para evitar infracciones de integridad referencial puede proporcionarse un cuadro de
lista con entradas válidas. Si las entradas válidas son demasiado largas y no caben en un
cuadro de lista, permitase que el usuario especifique criterios de búsqueda y muestrese
después una lista de entradas válidas.
Por ejemplo, cuando agrega un nuevo producto, se puede permitir al usuario escribir un
valor para un nombre de producto y a continuación mostrar una cuadrícula con todos los
productos que coincidan con ese nombre. Seguidamente, el usuario puede seleccionar un
producto válido de la cuadrícula.
Transacciones:
Una transacción es una serie de cambios realizados en una base de datos. Pueden
agruparse varios cambios de bases de datos en una transacción.
Si todas las operaciones se realizan correctamente, confirmará la transacción. Si alguna
de las operaciones falla, deshará la transacción.
Métodos de transacciones:
Los métodos de transacciones se aplican al objeto Workspace. Se Utiliza el método
BeginTrans antes de actualizar el primer registro. Si alguna de las siguientes actualizaciones
falla, se utiliza el método Rollback para deshacerlas todas. Se usa el método CommitTrans
tras haber actualizado correctamente el último registro.
El siguiente fragmento de código muestra la utilización de transacciones con el fin de
agregar un entrada a la tabla Pedidos y a la tabla Detalles de pedidos:
Sub cmdAddOrder_Click ()
On Error GoTo AddOrder_Err
DBEngine.WorkSpaces(0).BeginTrans
db.Execute "Insert Into Pedidos...", dbFailOnError
db.Execute "Insert Into [Detalles de pedidos]..." , dbFailOnError
DBEngine.WorkSpaces(0).CommitTrans
lblStatus.Caption = "Actualizaciones terminadas"
Exit Sub
AddOrder_Err:
lblStatus.Caption = Err.Description
Msgbox "No se han efectuado todas las actualizaciones con éxito"
DBEngine.Workspaces(0).Rollback
52
Manual del Alumno
Exit Sub
End Sub
Utilizar transacciones para mejorar el rendimiento:
Además de utilizar las transacciones para mantener la integridad de los datos, puede
mejorarse el rendimiento si se incluye una instrucción Update de SQL en una transacción.
Las operaciones de la transacción se almacenan en búfer y no se escriben a disco hasta que
se confirma la transacción.
El siguiente ejemplo incluye una instrucción Update de SQL en una transacción:
DBEngine.Workspaces(0).BeginTrans
stSQL = "UPDATE Productos SET [PrecioUnidad] = [PrecioUnidad] * 0.1"
db.Execute strSQL, dbFailOnError
DBEngine.Workspaces(0).CommitTrans
Nota Es posible anidar transacciones en un objeto Workspace. Se deberá confirmar o
deshacer la transacción actual antes de poder confirmar o deshacer una transacción de un
nivel superior.
Si se desea disponer de transacciones que se solapen pero que sean independientes
entre sí, puede crearse un segundo objeto Workspace.
Para obtener más información acerca de la creación de objetos Workspace, veáse el
método CreateWorkspace en la Ayuda de Visual Basic.
Consideraciones multiusuario:
Las aplicaciones de bases de datos se vuelven más complejas si se desea permitir que
varios usuarios tengan acceso a una base de datos simultáneamente. Deberán tratar diversos
errores que pueden producirse cuando varios usuarios tengan acceso a los mismos datos. Por
ejemplo:
 Dos usuarios tratan de modificar los mismos datos: El motor de base de datos
Microsoft Jet bloquea automáticamente los datos para evitar que dos usuarios
modifiquen un registro simultáneamente. Si los usuarios tratan de actualizar un
registro bloqueado, recibirán un error de tiempo de ejecución.
 Alguien cambia un registro que otro usuario está viendo: Si un usuario intenta
actualizar un registro y los datos se han modificado desde que se ejecutó el método
Edit, el motor de base de datos Microsoft Jet devolverá un error.
 Alguien elimina un registro que otro usuario está viendo: Si un usuario intenta
tener acceso a un registro que se ha eliminado, el motor de base de datos Microsoft
Jet devolverá un error.
Abrir una tabla para acceso exclusivo:
53
Manual del Alumno
Para evitar los problemas que ocurren cuando se permite que varios usuarios tengan
acceso a una base de datos, puede abrirse un tabla para uso exclusivo. Al abrirse una tabla de
este modo se evita que otro usuario la utilice. Aunque se trata de una solución bastante
restrictiva, puede resultar adecuada para tal situación.
El argumento opciones para el método OpenRecordset determina cómo se abre el
Recordset.
En el código siguiente se abre una tabla para uso exclusivo. Puede modificarse la tabla
Pedidos, pero ningún otro usuario podrá ver ni modificar los datos de dicha tabla:
Set recOrders = dbMydb.OpenRecordset _
("Pedidos", dbOpenTable, dbDenyRead + dbDenyWrite)
En el código siguiente se abre una tabla para escritura en modo exclusivo. Puede verse
y modificarse la tabla Pedidos; los otros usuarios pueden ver los datos de la tabla, pero no
pueden modificarlos:
Set recOrders = dbMydb.OpenRecordset _
("Pedidos", dbOpenTable, dbDenyWrite)
En el código siguiente se abre un Recordset en modo de sólo lectura. Pueden leerse los
datos de la tabla, pero no modificarlos. Esto no afecta a los demás usuarios:
Set recOrders = dbMydb.OpenRecordset _
("Pedidos", dbOpenTable, dbReadOnly)
En el código siguiente se abre un Recordset en modo anexar. Sólo pueden agregarse
registros; no pueden verse ni modificar los registros existentes. Esto no afecta a los demás
usuarios:
Set recOrders = dbMydb.OpenRecordset _
("Pedidos", dbOpenDynaset, dbAppendOnly)
Si sólo se desea agregar registros a una tabla, debe utilizarse la opción dbAppendOnly
para obtener mayor rendimiento. La opción dbDenyRead sólo está disponible en el
Recordset de tipo table.
Para obtener una lista de valores válidos para el argumento opciones, veáse el método
OpenRecordset en la Ayuda de Visual Basic.
El bloque de Microsoft Jet:
Todos los sistemas de administración de bases de datos proporcionan algún tipo de
mecanismo de bloqueo para evitar que dos usuarios actualicen datos simultáneamente.
El motor de base de datos Microsoft Jet proporciona un bloqueo de página. Las páginas
son bloques de registros de 2048 bytes (2 KB) de tamaño. Visual Basic almacena tantos
registros como quepan en cada página. Cuando Visual Basic bloquea la página que contiene
un registro que está modificando, todos los demás registros de esa página también quedarán
bloqueados.
54
Manual del Alumno
Nota La información aquí consignada es específica de las bases de datos que utilizan
el motor Microsoft Jet. Cuando se tiene acceso a bases de datos a través de ODBC, el
mecanismo de bloqueo está controlado por el sistema de administración de bases de datos.
Bloqueo pesimista frente a bloqueo optimista:
El valor de la propiedad LockEdits del objeto Recordset determina cuándo se activa
un bloqueo para los registros del Recordset.
Bloqueo pesimista:
Si la propiedad LockEdits tiene el valor True, el bloqueo pesimista está activo. La
página que contiene el registro actual se bloquea en el momento en que utiliza el método
Edit. La página se desbloquea cuando utiliza el método Update.
La estrategia de bloqueo predeterminada bloquea los registros durante un período de
tiempo mayor, pero garantiza que después de ejecutarse el método Edit ningún otro usuario
pueda modificar los datos.
Bloqueo optimista:
Si la propiedad LockEdits tiene el valor False, el bloqueo optimista está activo. La
página que contiene el registro sólo se bloquea mientras se actualiza el registro.
Los bloqueos permanecen activos durante un período de tiempo más corto y varios
usuarios pueden utilizar el método Edit sin bloquear la página. No obstante, en este caso
deberán tratarse los posibles errores cuando el usuario ejecute el método Update.
Si se piensa que los usuarios no intentarán modificar el mismo registro a menudo,
considerese la posibilidad de asignar a la propiedad LockEdits el valor False.
Desbloqueo:
El motor de base de datos Microsoft Jet marca una página para que se desbloquee en
cuanto se complete la actualización. Sin embargo, los bloqueos se quitan realmente cuando
no se produce ninguna otra acción.
Puede utilizarSE el método Idle del objeto DBEngine con la opción dbFreeLocks
para suspender el proceso y permitir al motor de base de datos Microsoft Jet liberar los
bloqueos y seguir con las otras tareas en segundo plano, como muestra el siguiente código:
DBEngine.Idle dbFreeLocks
Controlar los errores de bloqueo:
Cuando varios usuarios están actualizando una base de datos, deberá agregarse código
que intercepte los errores siguientes:
 3260: No se pudo actualizar; actualmente está bloqueado: Se produce en el
método Edit cuando el registro está bloqueado. El código debe esperar unos
instantes y tratar de aplicar Edit otra vez o informar al usuario del error.
55
Manual del Alumno
 3186: No se pudo guardar el registro; bloqueado actualmente: Se produce en el
método Update cuando el registro está bloqueado. El código debe esperar unos
instantes y volver a intentarlo o informar al usuario del error.
 3197: Los datos han cambiado; la operación se ha detenido: Se produce en el
método Update o Edit si otro usuario cambió los datos desde la última vez que
tuvo acceso a ellos. El código debe actualizar el formulario con los datos más
recientes o informar al usuario del error.
Para obtener una lista completa de los errores disponibles en Visual Basic, veáse
Errores interceptables en la Ayuda de Visual Basic.
Tratar errores en Edit
El siguiente código de ejemplo muestra como tratar los errores de bloqueo que pueden
ocurrir en el método Edit:
Private Sub cmdEdit_Click()
On Error GoTo HandleError
rs.Edit
ButtonEditAddMode
Exit Sub
HandleError:
Select Case Err.Number
Case 3260 'la página está bloqueada actualmente
MsgBox "El registro está bloqueado actualmente. Inténtelo más
tarde."
Case 3197 'los datos han cambiado
MsgBox "Los datos han cambiado y se van a actualizar."
rs.Bookmark = rs.Bookmark 'obtener datos actualizados
FillFields
rs.Edit
Case Else
MsgBox Err.Number & ": " & Err.Description
End Select
End Sub
Si el registro está bloqueado cuando el usuario ejecuta el método Edit, se mostrará un
mensaje; si los datos han cambiado, el código actualizará el formulario con los datos más
recientes.
La instrucción recOrders.Bookmark = recOrders.Bookmark actualiza el registro
actual del Recordset con los datos más recientes de la base de datos.
Tratar errores en Update:
56
Manual del Alumno
El siguiente código de ejemplo muestra como tratar los errores de bloqueo que pueden
ocurrir en el método Update:
Private Sub cmdSave_Click()
Dim answer As Integer
On Error GoTo HandleError
rs.Fields("NombreCategoría") = txtCategoryName.Text
rs.Fields("Descripción") = txtDescription.Text
rs.Update
rs.Bookmark = rs.LastModified
FillFields
ButtonNonEditAddMode
Exit Sub
HandleError:
Select Case Err.Number
Case 3260
MsgBox "El registro está bloqueado actualmente. " & _
"Intente guardarlo más tarde o cancele los cambios."
Case 3197
answer = MsgBox("Los datos han sido modificados por otro
usuario. " & _ "¿Sobrescribir cambios?", vbYesNo)
If answer = vbYes Then
Resume
Else
rs.Bookmark = rs.Bookmark 'actualizar con cambios de
'otros usuarios
cmdCancel_Click
End If
Case Else
MsgBox Err.Number & ": " & Err.Description
End Select
End Sub
Tratar errores de los registros eliminados por otros usuarios:
Cuando el Recordset de tipo dynaset se ha llenado por completo, si otro usuario
elimina un registro de la base de datos, el puntero a esa entrada no se eliminará del dynaset.
Sin embargo, dicho registro ya no aparecerá en la base de datos. No podrá verse y se
producirá un error si se intenta tener acceso a los datos de ese registro.
La forma más sencilla de tratar este error es eliminar la entrada que hace referencia al
registro eliminado del dynaset.
El siguiente fragmento de código muestra cómo tratar un error generado por un intento
de tener acceso a un registro eliminado:
57
Manual del Alumno
Private Sub cmdMoveNext_Click()
On Error GoTo err_movefirst:
retry_MoveNext:
rs.MoveNext
txtLName.Text = rs("Apellidos") 'Puede ocurrir un error
Exit Sub
err_Movefirst:
If Err.Number = 3167 Then
'se borra el registro,
'eliminar la entrada del dynaset
rs.Delete
Resume retry_MoveNext
Else
MsgBox Err.Description
Exit Sub
End If
End Sub
Anteriormente, se dedicó gran parte a explicar el objeto Recordset y se comentó acerca
de la creación y manipulación de estos. Seguidamente, se brinda un reforzamiento de
conceptos al respecto.
Acceso a bases de datos externas:
Desde Visual Basic puede tenerse acceso a diversas bases de datos ISAM (Método de
acceso secuencial indizado) como dBASE, Paradox, Btrieve y Microsoft Visual FoxPro.
Visual Basic proporciona controladores para diversas bases de datos ISAM. Estos
controladores se muestran en el registro.
También puede utilizar Visual Basic para tener acceso a archivos de datos estándar,
como archivos de texto delimitados por comas.
Nota Las bases de datos que utilizan el motor de base de datos Microsoft Jet se
consideran nativas de Visual Basic.
Opciones de acceso:
Hay dos formas de tener acceso a los datos de una base de datos externa: adjuntar la
base de datos externa y abrirla directamente.
Adjuntar una tabla a una base de datos de Microsoft Jet:
Cuando se adjunta una base de datos externa a una base de datos de Microsoft Jet, los
datos de la tabla permanecen en la base de datos externa. Sin embargo, la información de
conexión y la definición de la tabla se almacenan en la base de datos de Microsoft Jet. Puede
58
Manual del Alumno
utilizarse la tabla como cualquier otra tabla de bases de datos de Microsoft Jet, a excepción
de que no puede crear un Recordset de tipo table en una tabla adjunta.
Puede utilizarse Microsoft Access para adjuntar fácilmente una tabla a una base de
datos de Microsoft Jet. También puede adjuntarse una tabla por programa mediante Visual
Basic.
Para obtener información acerca de cómo adjuntar tablas por programa, veáse el
método CreateTableDef en la Ayuda de Visual Basic.
Nota Normalmente puede tenerse acceso más rápidamente a los datos de las tablas
ODBC que se adjuntan a una base de datos de Microsoft Jet que a los datos de una base de
datos ODBC que haya abierto directamente. Si es posible, considerese la posibilidad de
adjuntar tablas externas en lugar de abrirlas directamente.
Abrir una tabla directamente:
Cuando se abre directamente una tabla externa, debe especificarse la información de
conexión mediante los argumentos del método OpenDatabase o la propiedad Connect del
control Data.
El siguiente fragmento de código muestra como utilizar los métodos OpenDatabase y
OpenRecordset para abrir una tabla directamente:
59
Manual del Alumno
Sub OpenTable()
Dim wspCurrent As Workspace
Dim dbCurrent As Database
Dim rstProducts As Recordset
Set wspCurrent = CreateWorkspace("New Workspace", "Admin", "", _
dbUseJet)
Set dbCurrent = wspCurrent.OpenDatabase("C:\Archivos de _
programa\DevStudio\VB\Inventario.mdb")
Set rstProducts = dbCurrent.OpenRecordset("Productos", dbOpenTable)
rstProducts.MoveLast
MsgBox "Hay " & rstProducts.RecordCount & " registros."
rstProducts.Close
dbCurrent.Close
wspCurrent.Close
End Sub
Acceso a bases de datos ISAM:
Para abrir una base de datos ISAM directamente, debe asignarse al argumento
Database del método OpenDatabase (o a la propiedad DatabaseName del control Data) el
nombre de la carpeta que contiene las tablas ISAM. Si la red lo admite, puede utilizar una
ruta de acceso de red para el nombre de la base de datos, por ejemplo,
“\\mi_servidor\mi_recurso”.
Asignese a la propiedad Connect del objeto Database o del control Data el tipo de
base de datos que se va a abrir. Para obtener una lista de valores posibles, veáse la propiedad
Connect en la Ayuda de Visual Basic.
En el ejemplo siguiente se abre directamente una base de datos de Microsoft Visual
FoxPro:
Public Sub OpenFoxProTable()
Dim dbFox As Database
Dim recAccounts As Recordset
Set dbFox = OpenDatabase _
("\\FoxPro\Data\AP", False, False, “FoxPro 5.0;") ‘direccionado a la red.
Set recAccounts = dbFox.OpenRecordset("Cuentas")
End Sub
Para adjuntar una base de datos ISAM a una base de datos .mdb existente, debe crearse
un nuevo objeto TableDef y establecer las propiedades Connect y SourceTableName del
objeto TableDef.
En el ejemplo de código siguiente se adjunta una tabla de Microsoft FoxPro a una base
de datos de Microsoft Jet. Puede crearse una nueva base de datos de Microsoft Jet o bien
utilizar una existente:
Dim tbdAttach as TableDef
Set dbMydb=OpenDatabase ("Mibd.mdb")
Set tbdAttach = dbMydb.CreateTableDef ("Tabla FoxPro adjunta")
60
Manual del Alumno
tbdAttach.Connect = "FoxPro 5.0;DATABASE=\\FoxPro\AP"
tbdAttach.SourceTableName = "Cuentas"
dbMydb.TableDefs.Append tbdAttach
Cuando se haya adjuntado la tabla a una base de datos de Microsoft Jet, podrá abrirse
de la forma siguiente:
Set dbMydb = OpenDatabase ("Mibd.mdb")
Set recAttach = dbMydb.OpenRecordset ("Tabla FoxPro adjunta")
Distribuir el ejecutable:
Cuando se distribuya una aplicación que tenga acceso a una base de datos ISAM,
deberá proporcionarse al usuario los controladores ISAM adecuados.
Trabajando con archivos de datos:
Pueden crearse aplicaciones de Visual Basic que trabajen con información de archivos
de datos estándar en lugar de hacerlo con una base de datos.
Cuando se trabaje con información procedente de archivos de datos estándar, pueden
utilizarse alguna de las siguientes opciones:
 Instrucciones de E/S de archivos: Puede utilizar las instrucciones estándar de
acceso a archivos de Visual Basic para leer y escribir archivos. Para obtener más
información acerca de la instrucción Open, vea Open en la Ayuda de Visual Basic.
 Importación manual a una base de datos: Puede utilizar Microsoft Access para
importar manualmente un archivo de texto a una base de datos. Microsoft Access
admite diversos formatos de archivo, como de longitud fija, delimitados por comas,
etc.
 Importación mediante programación a una base de datos: Puede crear un
programa que lea un archivo de texto y agregue los datos a una base de datos.
61
Manual del Alumno
El siguiente código de ejemplo muestra los pasos básicos para utilizar la E/S de
archivo con el fin de leer un archivo e insertar los datos en una base de datos:
Private Sub Command4_Click()
Dim fhandle As Integer
fhandle = FreeFile()
Open "newCust.txt" For Input As fhandle
Do
'Leer archivo utilizando alguna instrucción Input
'Crear cadena sql
'Ejecutar instrucción Insert de SQL
Loop Until EOF(fhandle)
End Sub
Acceso a datos mediante ODBC:
La versión 3.5 de DAO presenta una nueva tecnología de conexión cliente-servidor
llamada Open Database Connectivity Direct (ODBCDirect). Esta tecnología establece una
conexión directamente con un origen de datos ODBC, sin cargar el motor de base de datos
Microsoft Jet.
Definir un espacio de trabajo ODBC:
La tecnología de ODBCDirect permite tener acceso directamente a orígenes de datos
ODBC mediante Objetos de acceso a datos (DAO). Pueden utilizarse las características de
esta conexión cliente-servidor para tener acceso rápidamente a una base de datos, sin cargar
el motor de base de datos Microsoft Jet.
El primer paso para utilizar ODBCDirect consiste en definir el tipo de espacio de
trabajo que utilizará. Puede hacerse de dos formas: establecer el tipo de espacio de trabajo
predeterminado o definir un tipo de espacio de trabajo específico como ODBCDirect.
Establecer el espacio de trabajo predeterminado:
Para establecer el tipo de espacio de trabajo predeterminado como ODBCDirect, debe
utilizarse la propiedad DefaultType del objeto DBEngine. Este tipo se utilizará siempre que
se cree un objeto Workspace.
Para definir un tipo de espacio de trabajo específico como ODBCDirect, debe
asignarse a la propiedad DefaultType el valor dbUseODBC. Este valor impide que el motor
de base de datos Microsoft Jet se cargue en memoria, si no ha creado ya un espacio de
trabajo de base de datos de Microsoft Jet.
62
Manual del Alumno
El código siguiente establece el tipo de espacio de trabajo predeterminado como
ODBCDirect:
DBEngine.DefaultType = dbUseODBC
Crear un espacio de trabajo específico:
Puede invalidarse el valor de espacio de trabajo predeterminado para un determinado
espacio de trabajo si utiliza el argumento tipo del método CreateWorkspace.
Conectarse a un origen de datos remoto:
Conectarse con un origen de datos remoto es similar a abrir una base de datos de
Microsoft Jet. Primero debe crearse un espacio de trabajo (como un espacio de trabajo de
ODBCDirect) y después abrir el origen de datos.
Para abrir un origen de datos remoto, debe crease un objeto Connection de la misma
forma en que se crearía un objeto Database para abrir una base de datos de Microsoft Jet.
Una vez creada una conexión, pueden recuperarse datos del origen de datos remoto.
Declaración de la conexión:
La variable de objeto Connection se refiere a su conexión. Utilicese la instrucción Set
para abrir la conexión.
El código siguiente abre una conexión en el espacio de trabajo predeterminado:
Dim conNewConnection As Connection
Set conNewConnection = OpenConnection _
("New", dbDriverPrompt, False, _
"ODBC;DATABASE=pubs;UID=sa;PWD;DSN=SQLServer")
Método OpenConnection:
En la tabla siguiente se enumeran los argumentos del método OpenConnection y se
describe su uso.
63
Manual del Alumno
Argumento
Nombre
Opciones
Solo_lectura
Conexión
Descripción
Cualquier cadena, si especifica un nombre de origen de datos (DSN) ODBC
registrado. Si en la declaración de OpenConnection no se incluye un DSN
válido, el nombre deberá hacer referencia a un DSN válido de ODBC, que
también será la propiedad Name.
Establece diversas opciones para la conexión.
True o False. Si es True, no se permiten modificaciones. El valor
predeterminado es False.
Una cadena de conexión ODBC.
El argumento opciones determina si y cuándo se pedirá al usuario que establezca la
conexión y si la conexión se abrirá o no de manera asíncrona.
En la tabla siguiente se muestran los valores del argumento opciones y se describe su
uso.
Constante
dbDriverNoPrompt
Resultado
El Administrador de controladores ODBC utiliza la cadena de conexión
proporcionada en el argumento conexión
El Administrador de controladores ODBC muestra el cuadro de diálogo
dbDriverPrompt
Seleccionar origen de datos, que presenta toda la información relevante
proporcionada en el argumento conexión. La cadena de conexión está
formada por el DSN seleccionado por el usuario mediante los cuadros de
diálogo o bien, si el usuario no especifica ningún DSN, se usará el DSN
predeterminado.
Si el argumento conexión incluye toda la información necesaria para
dbDriverComplete
completar una conexión, el Administrador de controladores ODBC usará
la cadena del argumento conexión. De lo contrario, se comportará como
cuando especifica la constante predeterminada dbDriverPrompt. Es el
valor predeterminado.
dbDriverCompleteR Esta opción se comporta como la constante dbDriverComplete, excepto
en que el controlador ODBC desactiva las peticiones de información
equired
innecesarias para completar la conexión
Ejecuta el método de forma asíncrona. Esta constante se puede utilizar
dbRunAsync
con cualquiera de las demás constantes de opciones
64
Manual del Alumno
Recuperar datos remotos:
La recuperación de datos remotos mediante ODBCDirect es muy similar a la
recuperación de datos desde una base de datos de Microsoft Jet. Después de establecer una
conexión con una base de datos compatible con ODBC mediante ODBCDirect, cree un
objeto Recordset; para ello, utilicese el método OpenRecordset de la misma forma que si se
recuperaran registros de una base de datos de Microsoft Jet.
Declaración del Recordset:
El siguiente ejemplo de código crea un espacio de trabajo de ODBCDirect con una
conexión al espacio de trabajo y después recupera un Recordset:
Sub OpenODBCDirectRecordset()
Dim wspODBC As Workspace
Dim conODBC As Connection
Dim rstODBC As Recordset
Set wspODBC = CreateWorkspace _
("", "sa", "", dbUseODBC)
Set conODBC = wspODBC.OpenConnection _
("NewConnection", dbDriverNoPrompt, False, _
"ODBC;DATABASE=pubs;UID=sa;PWD=;DSN=SQLServer")
Set rstODBC = conODBC.OpenRecordset _
("SELECT * FROM Autores WHERE au_lname = 'Enrique Gómez'",
_
dbOpenSnapshot, 0, dbReadOnly)
rstODBC.MoveLast
MsgBox "Este conjunto de datos remoto contiene " & _
rstODBC.RecordCount & " registros."
rstODBC.Close
conODBC.Close
wspODBC.Close
End Sub
El Recordset recuperado de un origen de datos remoto se puede controlar de la misma
forma que un Recordset recuperado mediante DAO con el motor de base de datos Microsoft
Jet.
Método OpenRecordset con ODBCDirect:
Además de las opciones disponibles en el método OpenRecordset de un objeto
Database, el método OpenRecordset de un objeto Connection permite recuperar registros
de una base de datos.
Cuando se utiliza un espacio de trabajo de ODBCDirect están disponibles los
siguientes argumentos del método OpenRecordset:
Tipo:
—
dbOpenDynamic
65
Manual del Alumno
Abre un Recordset de tipo dynamic que puede utilizar para agregar, cambiar o eliminar
registros de una o varias tablas de una base de datos subyacente. Un cursor dinámico puede
contener campos de una o más tablas de una base de datos.
Opciones:
—
dbRunAsync
Ejecuta una consulta asíncrona. Una consulta asíncrona es aquella en que las
consultas SQL devuelven el control inmediatamente, incluso aunque los resultados no estén
preparados. Esto permite que una aplicación efectúe otros procesos mientras la consulta se
termina.
—
dbExecDirect
Ejecuta una consulta; para ello elude SQLPrepare y llama directamente a
SQLExecDirect. Utilice esta opción sólo cuando no vaya a abrir un Recordset basado en
una consulta de parámetros.
®
ediciones_bloqueo
—
dbOptimisticValue
Utiliza la concurrencia optimista basada en valores de fila.
—
dbOptimisticBatch
Activa la actualización optimista por lotes.
Nota El espacio de trabajo predeterminado de ODBCDirect es de sólo lectura. Para
que los usuarios puedan leer y escribir registros en un espacio de trabajo de ODBCDirect,
debe especificarse el tipo de bloqueo dbOptimistic. Para obtener información acerca de los
tipos de bloqueo, veáse el método OpenRecordset en la Ayuda de Visual Basic.
66
Manual del Alumno
Problemas de rendimiento:
El diseño de una aplicación afecta en gran medida a su rendimiento. Cuando se
desarrollen aplicaciones de base de datos, tengase en cuenta las siguientes sugerencias:
 Analícese lo que se requiere: Algunas consultas SQL son más eficientes que otras.
Por ejemplo, ordenar por un campo que contiene un índice es más rápido que
ordenar por un campo que no contiene un índice.
Para obtener más información acerca de la optimización de consultas, busque
Sugerencias de rendimiento y solución de problemas en los Libros en pantalla de
Visual Basic y haga clic en Sugerencias de rendimiento y solución de problemas.
 Solicitar únicamente los datos que necesite: No crear Recordsets de tipo dynaset y
snapshot en toda una tabla. El diseño de una aplicación debe permitir al usuario
especificar criterios y devolver un Recordset limitado.
En lugar de seleccionar todas las columnas de un registro, deben seleccionarse
únicamente las columnas necesarias.
El código siguiente crea un Recordset basándose en un valor especificado por el
usuario. Por ejemplo, si el usuario escribe “A”, el código creará un Recordset de
todos los empleados cuyo apellido empiece por “A”:
strSQL = "Select [Apellidos], [Nombre] From Empleados " & _
"Where [Apellidos] Like " & _
"'" & txtName.Text & "'" & "*"
Set recEmployees = dbMydb.OpenRecordset (strSQL,dbOpenDynaset)
 Utilizar únicamente la funcionalidad necesaria: Si no se necesita actualizar la base
de datos, ábrase de sólo lectura. Esto mejora el rendimiento, ya que el motor de
base de datos Microsoft Jet no necesita hacer un seguimiento de los bloqueos.
Si no se necesita actualizar un Recordset, ábrase como de sólo lectura.
Si sólo se va a agregar a un Recordset, ábrase con la opción dbAppendOnly.
 Utilizar transacciones: Utilizar una transacción reduce el acceso a disco a una vez
por transacción, no una vez por registro, lo cual puede mejorar considerablemente
el rendimiento de una aplicación. Puede que se desee agrupar transacciones. Si una
transacción es demasiado grande, utilizará memoria que pueden necesitar otras
operaciones.
 Utilizar consultas almacenadas: En general, es mejor crear consultas almacenadas
que utilizar SQL en el texto. Una consulta almacenada está precompilada, por lo
que ahorrará tiempo de compilación durante la ejecución. Además, normalmente es
más sencillo mantener consultas que están almacenadas en un archivo .mdb que las
creadas mediante aplicación.
Si es posible, utilice consultas almacenadas o SQL para las operaciones por lotes,
como la actualización de un grupo de registros, en lugar de actualizar los registros
de uno en uno con el método Update.
67
Manual del Alumno
 Adjuntar tablas SQL: Adjuntar tablas de bases de datos ODBC a una base de datos
.mdb local. La información de conexión y de definición de datos se mantiene con el
archivo .mdb y, por tanto, mejora el rendimiento.
 Escribir sus propias pruebas de rendimiento: Hay muchos factores que afectan al
rendimiento de una aplicación. La mejor manera de averiguar si una característica
mejorará el rendimiento es probarla con los datos de su entorno.
Práctica No. 17
 Diseñe el siguiente formulario:
 Escriba el siguiente codigo en las declaraciones generales del formulario:
Public CodDML As Integer
Public Mensaje, TituloBarra As String
Function Ver_Forma2()
Form2.Show
End Function
Function Habilita_Textos()
If CodDML = 0 Then
68
Manual del Alumno
Text1.Enabled = True
End If
Text2.Enabled = True
Text3.Enabled = True
Text4.Enabled = True
End Function
Function DesHabilita_Textos()
If CodDML = 0 Then
Text1.Enabled = False
End If
Text2.Enabled = False
Text3.Enabled = False
Text4.Enabled = False
End Function
Function Descubre_Botones()
Incluir.Visible = True
Anterior.Visible = True
Siguiente.Visible = True
Final.Visible = True
Inicio.Visible = True
Modificar.Visible = True
Excluir.Visible = True
Cerrar.Visible = True
Aceptar.Visible = False
Cancelar.Visible = False
End Function
Function Esconde_Botones()
Incluir.Visible = False
Modificar.Visible = False
Excluir.Visible = False
Anterior.Visible = False
Siguiente.Visible = False
Final.Visible = False
Inicio.Visible = False
Cerrar.Visible = False
Aceptar.Visible = True
Cancelar.Visible = True
End Function
Private Sub Aceptar_Click()
Select Case CodDML
Case CodDML = 0
Data1.Recordset.Update
Case CodDML = 1
Data1.Recordset.Update
Case CodDML = 2
Data1.Recordset.Delete
End Select
69
Manual del Alumno
MsgBox Mensaje, 0 + 16 + 56, TituloBarra
Call Descubre_Botones
Call DesHabilita_Textos
End Sub
Private Sub Anterior_Click()
If Not Data1.Recordset.BOF Then
Data1.Recordset.MovePrevious
Siguiente.Enabled = True
Final.Enabled = True
If Data1.Recordset.BOF Then
Anterior.Enabled = False
Inicio.Enabled = False
Data1.Recordset.MoveFirst
MsgBox "Inicio de la tabla"
End If
End If
End Sub
Private Sub Buscar_Click()
Call Ver_Forma2
Data1.Recordset.FindFirst "[CEDULA] = 'ABuscar'"
If Data1.Recordset.NoMatch Then
MsgBox "NO se encuentra"
End If
End Sub
Private Sub Cancelar_Click()
Data1.Refresh
Call DesHabilita_Textos
Call Descubre_Botones
End Sub
Private Sub Cerrar_Click()
End
End Sub
Private Sub Excluir_Click()
CodDML = 2
Call Esconde_Botones
Call Habilita_Textos
Mensaje = "El Registro fue Exitosamente Eliminado"
TituloBarra = "Eliminado.."
End Sub
Private Sub Final_Click()
Data1.Recordset.MoveLast
Siguiente.Enabled = False
Final.Enabled = False
70
Manual del Alumno
Anterior.Enabled = True
Inicio.Enabled = True
End Sub
Private Sub Incluir_Click()
CodDML = 0
Call Esconde_Botones
Call Habilita_Textos
Mensaje = "El Registro fue Exitosamente almacenado"
TituloBarra = "Inclusión de Registros.."
Data1.Recordset.AddNew
End Sub
Private Sub Inicio_Click()
Data1.Recordset.MoveFirst
Anterior.Enabled = False
Inicio.Enabled = False
Siguiente.Enabled = True
Final.Enabled = True
End Sub
Private Sub Modificar_Click()
CodDML = 1
Call Esconde_Botones
Call Habilita_Textos
Data1.Recordset.Edit
Mensaje = "El Registro fue Exitosamente Modificado"
TituloBarra = "Modificación de Registros.."
Text2.SetFocus
End Sub
Private Sub Siguiente_Click()
If Not Data1.Recordset.EOF Then
Data1.Recordset.MoveNext
Anterior.Enabled = True
Inicio.Enabled = True
If Data1.Recordset.EOF Then
Data1.Recordset.MoveLast
Siguiente.Enabled = False
Final.Enabled = False
MsgBox "Final de la tabla"
End If
End If
End Sub
Private Sub Text1_KeyPress(Tecla As Integer)
71
Manual del Alumno
If Tecla = 13 Then
Text2.SetFocus
End If
End Sub
Private Sub Text2_GotFocus()
Text2.SelStart = 0
Text2.SelLength = Len(Text2.Text)
End Sub
Private Sub Text2_KeyPress(Tecla As Integer)
If Tecla = 13 Then
Text3.SetFocus
End If
End Sub
Private Sub Text3_GotFocus()
Text3.SelStart = 0
Text3.SelLength = Len(Text3.Text)
End Sub
Private Sub Text3_KeyPress(Tecla As Integer)
If Tecla = 13 Then
Text4.SetFocus
End If
End Sub
Private Sub Text4_GotFocus()
Text4.SelStart = 0
Text4.SelLength = Len(Text4.Text)
End Sub
Nota: La codificación anterior contiene algunos errores de forma y de fondo.
Corresponderá al estudiante corregirlas y culminar este ejemplo con o sin ayuda del profesor.
Asimismo, el profesor le explicará, paso a paso, la codificación del mismo.
Práctica No. 18
1. Cree una tabla en Microsoft Access o utilizando el VisData de Visual Basic, denominada
Nomina.Mdb y en ella una tabla del mismo nombre con los campos Id_depart(Text 15) y
dep_desc(text 30).
2. Diseñe el siguiente formulario y establezca en el Data Control la base de datos Nomina y
la tabla del mismo nombre.
72
Manual del Alumno
3. Escriba en cualquiera de los botones (los cuales son una matríz de controles) el siguiente
código:
Private Sub Barra_Click(Index As Integer)
Select Case Index
Case 0
If Barra(0).Caption = "Nuevo" Then
Data1.Recordset.AddNew
Barra(0).Caption = "Incluir"
Barra(1).Caption = "Cancelar"
CODIGO.Enabled = True
DESCRIPCION.Enabled = True
For a = 2 To 4
Barra(a).Visible = False
Barra(a).Enabled = False
Next
CODIGO.SetFocus
Else
Data1.Recordset!id_depart = CODIGO.Text
Data1.Recordset!dep_desc = DESCRIPCION.Text
On Error GoTo RUTINA_ERROR
Data1.Recordset.Update
On Error GoTo 0
Barra(0).Caption = "Nuevo"
Barra(1).Caption = "Editar"
CODIGO.Enabled = False
DESCRIPCION.Enabled = False
For a = 2 To 4
Barra(a).Visible = True
Barra(a).Enabled = True
Next
End If
Barra(0).Refresh
73
Manual del Alumno
Barra(1).Refresh
Case 1
If Barra(1).Caption = "Cancelar" Then
CODIGO.Text = ""
DESCRIPCION.Text = ""
Barra(0).Caption = "Nuevo"
Barra(1).Caption = "Editar"
For a = 2 To 4
Barra(a).Visible = True
Barra(a).Enabled = True
Next
Else
Data1.Recordset.Edit
Barra(0).Caption = "Modificar"
Barra(1).Caption = "Cancelar"
DESCRIPCION.Enabled = True
For a = 2 To 4
Barra(a).Visible = False
Barra(a).Enabled = False
Next
DESCRIPCION.SetFocus
End If
Barra(0).Refresh
Barra(1).Refresh
Case 2
Case 3
Case 4
End
End Select
RUTINA_ERROR:
Select Case Err.Number
Case 3022
Msg = "Registro Ya Existe en la Tabla"
MsgBox Msg, , "!!! PANTALLA DE ERRORES !!!"
Err.Clear ' Clear Err object fields
CODIGO.SetFocus
End Select
End Sub
74
Manual del Alumno
SQL
SQL es un lenguaje de programación de base de datos cuyas iniciales vienen de las
palabras inglesas Structured Query Language, que se puede traducir como Lenguaje
Estructurado de Búsqueda o Consulta. Este lenguaje está estrechamente relacionado con la
invención de la base de datos relacional hecha por E.F. Cood a principio de 1970.
El moderno SQL ha evolucionado ampliamente como un estandard en el manejo de
bases de datos relacionales, y está definido por los estandares ANSI. La mayoría de las
implementaciones de SQL tienen pequeñas diferencias de los estandares definidos
incluyendo la version soportada por el motor de bases de datos Microsoft Jet.
SQL Vrs. Navegación:
El motor de base de datos Microsoft Jet provee dos metodos separados para llevar a
cabo la mayoría de tareas relacionadas con las bases de datos:
 El modelo navegacional que consiste en ir accesando los registros de la base de datos.
 El modelo relacional que está basado en el lenguaje estructurado de búsqueda.
Para los programadores que están familiarizados con sistemas de bases de datos
basados/orientados a archivos como Dbase, Foxpro o Paradox podrían sentirse más comodos
utilizando el metodo navegacional. Sin embargo, en la mayoria de los casos el equivalente
utilizadndo el metodo SQL es mas eficiente y po lo tanto deberian ser tuilizados donde el
rendimiento o tiempo de respuesta es importante. Adicionalmente, SQL tiene la ventaja de
ser la interfase estandar de base de datos de diferentes porveedores, por lo tanto, el
conocimiento de comandos SQL permiten accesar y manipular una gran variedad de
productos de bases de datos.
Codificando consultas con SQL:
El SQL es usado para crear objetos QueryDef utilizandolo como parametro en el
metodo Recordset o en la propiedad de un Data Control. Tambien puede ser utilizado con el
metodo Execute para crear o manipular directamente bases de datos JET y para crear
consultas por Selección o por Acción.
Operaciones DML:
El SQL Data Manipulation Language (Lenguaje de manipulación de datos) son
utilizados para consultar, actualizar, crear o eliminar registros en las tablas de una base de
datos. Esto se realiza mediante el uso de varias instrucciones, pero la mayoría de ellas se
usan con la estructura general del query Select.
COMANDO
CREATE
DESCRIPCIÓN
Se usa para crear nuevas tablas, campos e
75
Manual del Alumno
índices.
Se usa para borrar tablas e índices.
Se usa para modificar tablas, añadiendo campos
o cambiando las definiciones.
Se usa para crear consultas a la base de datos,
según un criterio especificado.
Se usa para cargar datos en la base de datos.
Se usa para actualizar registros de tablas.
Se usa para borrar registros de tablas.
DROP
ALTER
SELECT
INSERT
UPDATE
DELETE
Operadores lógicos:
 AND
 OR
 NOT
Los operadores lógicos se utilizan para conectar expresiones, usualmente en la claúsula
WHERE. Ejemplo:
SELECT *FROM MyTable WHERE condition1 AND condition2
Operadores de comparación:
<
<=
>
>=
<>
BETWEEN
LIKE
IN
Menor que
Menor o igual que
Mayor que
Mayor o igual que
Diferente de
Entre
Parecido a
En
Ejemplo:
SELECT *FROM MyTable WHERE PubId = 5
Sintaxis:
SELECT SELECT [ALL] | DISTINCT | DISTINCTROW | [TOP n [PERCENT]]]
{*| Table.*}| [Table.]field1 [AS alias1] [,[table.]field2[AS alias2][,...]]}
FROM tableexpresion [, ...] [IN externaldatabase]
[WHERE ...]
76
Manual del Alumno
[GROUP BY ...]
[HAVING ...]
[ORDER BY ...]
[WITH OWNERACCESS OPTION]
SELECT field1[, field2[, ...]] INTO newtable [IN externaldatabase] FROM source
INSERT INTO target [IN externaldatabase] [(field1[,field2[, ...]])]
SELECT [source.]field1 [,field2[, ...]
FROM tableexpresion
Single record append query:
INSERT INTO target [(field1[,field2[, ...]]) VALUES (value1[,value2[, ...]])
DELETE [table.*] FROM table WHERE criteria
UPDATE table SET newvalue WHERE criteria;
Ejemplos SQL:
1. SELECT *FROM empleados;
2. SELECT empleados.depto, supervisores.supnombre FROM empleados;
INNER JOIN supervisores ;
WHERE empleados.dpto = supervisores.depto;
3. SELECT BirthDate AS Birth FROM empleados;
4. SELECT COUNT(empleadosID) As HeadCount FROM empleados;
5. SELECT LastName, FirstName, Title, Salary FROM empleados;
AS T1 WHERE Salary >= (SELECT Avg(Salary) FROM empleados;
WHERE T1.Title = empleados.titles) ORDER BY Title;
6. SELECT LastName, Salary FROM empleados WHERE Salary > 100000;
7. SELECT * FROM Orders WHERE ShippedDate = DateValue(‘01/02/1999’);
8. INSERT INTO Customers SELECT * FROM [New Customers];
9. INSERT INTO empleados (FirstName,LastName, Title);
VALUES (‘Gómez’,’Enrique’Enrique’,’Profesor’);
10. SELECT Title, Count(Title) AS Total FROM empleados;
WHERE Region = ‘Heredia’;
GROUP BY Title;
HAVING Count(Title) > 1;
11. SELECT Count(*) AS TotalOrders FROM orders;
12. SELECT IIF(PostalCode BETWEEN 98101 AND 99100, ‘Local’, ‘NonLocal’);
FROM publishers;
13. SELECT sum(UnitPrice*Quantity) AS [Total UK Sales];
77
Manual del Alumno
FROM orders;
INNER JOIN [Orders Details];
ON orders.OrderId = [Orders Details]. OrderId;
WHERE (ShipCountry = ‘UK’);
14. SELECT LastName, FirstName FROM empleados;
WHERE LastName LIKE ‘[A-D]*’;
15. SELECT Avg(Freight) AS [Average Freight] FROM orders WHERE Freight > 100;
16. SELECT Count (ShipCountry) AS [UK Orders];
FROM orders WHERE ShipCountry = ‘UK’;
17. SELECT DISTINCTROW CompanyName FROM customers;
INNER JOIN orders;
ON customer.customerID = orders.customerID;
ORDER BY CompanyName;
18. UPDATE orders;
SET orderAmount = orderAmount * 1.5;
Freight = Freight + (Freight * .10);
WHERE shipcountry = ‘UK’;
78
Manual del Alumno
ACCESOS EXTERNOS:
79
Manual del Alumno
80
Manual del Alumno
81
Manual del Alumno
82
Manual del Alumno