Escolar Documentos
Profissional Documentos
Cultura Documentos
displaylang=es&FamilyID=7554f536-8c28-4598-9b72-
ef94e038c891
Imaginemos que tenemos un script VBScript que ponemos como tarea programada para que comprima y enve
ficheros por correo a determinados destinatarios, que pueda incluir varios destinatarios, tanto en el campo
Para, CC como en el CCO y que, adems, cada correo pueda incluir ms de un archivo comprimido y cada
archivo comprimido pueda incluir ms de un fichero. Si queremos que el script no lleve las tareas en s dentro
del cdigo (mala cosa a la hora de reutilizarle con distintos datos, pues supone retocar el cdigo), si no que lea
lo que tiene que hacer de un fichero, el fichero resultante sera muy complejo, con arrays dentro de arrays y
diferentes separadores para cada uno de ellos, siendo la tarea de establecer y recuperar la informacin muy
dificultosa. Sin embargo, en una estructura de bases de datos, sera muy fcil leer esto, pues tendramos una
tabla de tareas, otra con los archivos comprimidos con una clave externa a la de tareas, otra de ficheros con
una clave externa a la de archivos, y otra de destinatarios y tipo de destinatario (Para, CC o CCO) con una
clave externa a la tabla de tareas. Bastara realizar las consultas pertinentes, con sus JOINS si fueran
necesarios, para recuperar la informacin de una forma muy sencilla. Este es un ejemplo en el que una base de
datos con Excel nos puede ayudar (sera mejor con Access y se podra tambien usar desde VBScript, pero tiene
el inconveniente de que para preparar los datos se necesita Access, y eso sale ms caro que Excel, al venir este
ltimo en los paquetes ms bsicos de Office).
En este artculo, veremos cmo se trabaja con un libro Excel desde VBScript usando ADODB.
Existen diferencias entre ambos proveedores, que se deben tener en cuenta a la hora de elegir uno u otro para
Con Jet podemos especificar si tendr o no encabezados la tabla en las porpiedades extendidas con
HDR=yes o HDR=No (de forma predeterminada se considera que s, por lo que si se omite HDR Jet
asumir que la primera fila son encabezados de columna), mientras que con el proveedor ODBC se
puede establecer si tiene o no encabezados con FirstRowHasNames=<valor> (valor es 1 en caso
verdadero y 0 en caso falso), pero no funciona, est de adorno, por lo que siempre ODBC considerar
que tiene encabezados de columnas (veas el artculo de la Knowledge Base 288343).
Las conexiones con Jet son de lectura/escritura, mientras que de forma predeterminada son de slo
lectura en el caso de ODBC, pudiendo cambiar este comportamiento estableciendo la propiedad
Readonly como False.
Para determinar los tipos de datos de las columnas, tanto Jet como ODBC examinan los primeros 8
registros y operan en consecuencia. Con Jet se puede establecer cuntas filas se examinarn para decidir
el tipo de datos, pero con ODBC no, siempre son 8 filas, pues a pesar de existir la propiedad
RowsToScan, que permite establecer el nmero de filas a examinar, sta no funciona y adems, si una
columna contiene cadenas que deben ser superiores a 255 caracteres pero ninguno de los valores de las
primeras 8 filas supera estos 255 caracteres, las cadenas que los superen sern truncadas. sto se puede
solucionar para libros de Excel posteriores a la versin 97 retocando el registro como se explica en el
artculo de la Knowledge Base 189897.
Como se puede ver en lo expuesto anteriormente, es mejor usar el proveedor Jet que el ODBC, siendo
preferible reservar el uso de ste cuando se tiene que acceder por fuerza va ODBC con un DSN ya creado.
Respecto a los tipos de datos de las columnas, como hemos visto antes, ADO lo decide en funcin del
contenido de stas. Esta decisin se hace en funcin de cul es el tipo que ms ocurrencias tiene, si el
numrico o el de cadena, sustituyendo los valores restantes por nulos. En caso de empate, decide que es
numrico, dejando como nulos las cadenas que se presenten. Por ello, cuando es necesario que los datos sean
mixtos, debemos almacenarlos como texto, de esa manera no perderemos las cadenas o los nmeros.
La informacin que se pasa al proveedor para la conexin es la ruta + nombre del libro y la versin. Como
versin de proveedor se debe usar la 4.0, pues la 3.51 no admite controladores Jet ISAM. Como versin de
Excel se pasa:
Veamos dos ejemplos de conexin con el proveedor OLE DB de Microsoft Jet. Los ejemplos consisten en dos
funciones que reciben la ruta ms nombre de un libro de Excel y devuelven un objeto ADODB.Connection
conectado al libro recibido como parmetro. La diferencia entre ambas estriba en la manera en la que se
especifica el proveedor OLE DB de Microsoft Jet, asignndolo a la propiedad Provider del objeto
ADODB.Connection o establecindolo en la propia cadena de conexin. Este es el ejemplo establecindolo
con la propiedad Provider:
'Establecemos el proveedor
ado_Conexion.Provider = "Microsoft.Jet.OLEDB.4.0"
'Vaciamos el objeto
'Vaciamos el objeto
Cuando queremos abrir un libro de Excel 2007, es necesario que establezcamos como proveedor
Microsoft.ACE.OLEDB.12.0. Por tanto, las dos funciones anteriores, para que contemplaran la
posibilidad de estar abriendo un libro de Excel 2007, podran recibir una booleana que lo especificase y
quedaran as:
'Esta es la versin que lo especifica con la propiedad Provider
ado_Conexion.Provider = "Microsoft.ACE.OLEDB.12.0"
str_Conexion = str_Conexion & "Extended Properties=Excel 12.0"
Else
ado_Conexion.Provider = "Microsoft.Jet.OLEDB.4.0"
str_Conexion = str_Conexion & "Extended Properties=Excel 8.0"
End If
'Vaciamos el objeto
Else
End If
'Vaciamos el objeto
Para establecer la conexin es necesario pasar el dato de Driver, siendo el de Excel ({Microsoft Excel
Driver (*.xls)}) el que se especifica y la ruta ms nombre del libro. Se puede especificar el proveedor, si
bien no es imprescindible, pues al recibir el dato de driver el objeto ya asume que se trata del proveedor OLE
DB de Microsoft para controladores ODBC. Otro dato que se debe pasar es el identificador de driver,
DriverId, cuyo valor ser (Accessing Data with ADO):
Como se trata de ODBC, se puede conectar usando un DSN (Data Source Name) definido o sin usar un DSN.
Al tratarse de libros Excel, y debido a que vamos orientados a abrir cualquier libro, no me parar en las
conexiones con DSN definido, slo veremos las conexiones sin DSN. La siguiente funcin recibe una ruta ms
nombre de libro y una booleana que cuando es verdadera implica que el libro es de la versin Excel 97:
If bol_97 Then
str_Version = "790"
Else
str_Version = "278"
End If
'Vaciamos el objeto
Set ado_Conexion = Nothing
Si queremos conectar a un libro Excel 2007, es necesario que establezcamos, en la cadena de conexin, como
proveedor {Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)}, as pues, podemos retocar la
anterior funcin para que reciba una booleana que especifique si es un libro de Excel 2007 o no:
If bol_97 Then
str_Version = "790"
Else
str_Version = "278"
End If
str_Conexion = _
"Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};"
Else
str_Conexion = _
"Driver={Microsoft Excel Driver (*.xls)};"
End If
'Vaciamos el objeto
Set ado_Conexion = Nothing
Cuando ser trata de conectar a libros de Excel 2007, es necesario instalar en el equipo los Componentes de
conectividad de datos de Office 2007. Una vez conectados, la forma de establecer la conexin depende de si
usamos OLE DB de Microsoft Jet o OLE DB de Microsoft para controladores ODBC:
Unindolo Todo
Function f_ConectarALibroExcel(str_Libro, _
bol_ODBC, _
bol_97) 'As ADODB.Connection
str_Version = "790"
str_Version = "278"
Else
End If
If bol_2007 Then
str_Conexion = _
"Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & _
"DriverId=" & str_Version & ";" & _
"Dbq=" & str_Libro
Else
str_Conexion = _
"Driver={Microsoft Excel Driver (*.xls)};" & _
"DriverId=" & str_Version & ";" & _
End If
Else
End If
'Vaciamos el objeto
Set ado_Conexion = Nothing
Con eso habremos, en una sola lnea, conectado al libro Excel que deseemos, con tan solo pasar su ruta y
nombre, si queremos conectar por ODBC o por Jet y su versin de Excel Cmodo, eh?
Los Datos
Como vimos antes, es importante que tengamos en cuenta que ADO considera la primera lnea siempre como
nombres de campo (siempre que no establezcamos lo contrario con HDR en el proveedor Jet; como vimos con
el proveedor ODBC, la primera lnea siempre ser considerada de encabezados). Esto quiere decir que los
datos los deberamos tener siempre con encabezados, pues si estos no existen, la primera lnea de datos la
perderemos y se convertir en los nombres de los campos (lo cual puede dar errores debido a caracteres
prohibidos, etc.). Tambin vimos que la estructura de los datos debe ser coherente, pues ADO lee las primeras
ocho lneas de datos para decidir qu tipo de dato tienen los campos.
Con ADO podemos leer hojas, rangos con nombre y rangos sin nombre.
Las hojas son lo que el ADO considera tablas de tipo tabla de sistema. A la hora de hacer referencia a una
hoja en una SQL, se debe aadir a su final un caracter de dolar ($) y al conjunto encerrarlo entre corchetes([]);
esto es, la hoja Tunidos, debe ponerse en la SELECT como [Tunidos$]. La siguiente funcin nos
devuelve un objeto ADODB.Recordset con los datos de la hoja recibida como parmetro. Esto lo hace con
la conexin que tambin recibe como parametro:
'Creamos el Recordset
Set rs_Consulta = CreateObject("ADODB.Recordset")
'Ejecutamos la consulta
rs_Consulta.Open str_Consulta, ado_Conexion
'Vaciamos el objeto
Set rs_Consulta = Nothing
Para obtener un Recordset con los datos de la tabla, es tan simple como esto:
Sealar que es tambin posible encerrar el nombre de la hoja entre acentos graves, en lugar de corchetes; es
decir, es lo mismo [Tunidos$] que `Tunidos$`
Los rangos con nombre son lo que el driver considera tablas de tipo tabla. Se consultan igual que las hojas,
pero poniendo el nombre sin ms, no es necesario encerrar entre corchetes o acentos graves, ni poner un dolar
al final del nombre de la tabla; para tener esto en cuenta, podramos cambiar la anterior funcin para indicarle,
por medio de una booleana, si se trata de un rango con nombre o de una hoja:
Function f_RsTablaExcel(ado_Conexion, _
str_Tabla, _
bol_Hoja) 'As ADODB.Recordset
End If
'Montamos la consulta
str_Consulta = _
"SELECT " & vbCrLf & _
" * " & vbCrLf & _
"FROM " & vbCrLf & _
" " & str_Origen
'Creamos el Recordset
Set rs_Consulta = CreateObject("ADODB.Recordset")
'Ejecutamos la consulta
rs_Consulta.Open str_Consulta, ado_Conexion
'Vaciamos el objeto
Set rs_Consulta = Nothing
Tambin es posible leer directamente el rango que queramos sin que ste tenga nombre. Para ello,
especificamos la hoja y las coordenadas de ese rango. La sintaxis es:
Por ejemplo, para referirnos al rango A1:F24 de la hoja Tunidos, lo haramos como
[Tunidos$A1:F24]. Podramos retocar la funcin anterior para que nos permita especificar un rango
dentro de una hoja. Ser necesario que la booleana la pasemos como True:
End If
'Montamos la consulta
str_Consulta = _
"SELECT " & vbCrLf & _
" * " & vbCrLf & _
"FROM " & vbCrLf & _
" " & str_Origen
'Creamos el Recordset
Set rs_Consulta = CreateObject("ADODB.Recordset")
'Ejecutamos la consulta
rs_Consulta.Open str_Consulta, ado_Conexion
'Vaciamos el objeto
Set rs_Consulta = Nothing
Podemos listar las tablas de un libro usando el mtodo OpenSchema del objeto ADODB.Connection que
No obstante, tanto date_created como date_modified muestran siempre la misma fecha, que es la de ltima
modificacin; as pues, realmente, slo tres de los cuatro campos son fiables: table_name, table_type
y date_modified.
Esta es la teora, la prctica nos demuestra otra cosa: table_type es siempre de tipo TABLE,se trate de
hojas o de rangos con nombre. As pues, la nica manera que tenemos de averiguar si se trata de uno u otro
tipo es si aparece el caracter de dolar ($) al final del nombre; si es as, se trata de una hoja, si no, de un rango.
El siguiente mtodo recibe la ruta ms nombre de un libro de Excel y muestra por pantalla los nombres de sus
tablas y rangos con nombre:
Const adSchemaTables = 20
Else
End If
WScript.Echo str_Linea
Wend
Para volcar los datos de una consulta, podemos usar un mtodo como el que sigue. El mtodo recibe un objeto
ADODB.Recordset y muestra por pantalla los datos que contiene. Este es un mtodo tpico a la hora de
recorrer los registros de un Recordset cualquiera, da igual que sea ADO, DAO, etc.
Sub s_VolcarDatosRS (rs_Tabla)
'Almacenamos el nombre
str_Linea = str_Linea & _
rs_Tabla.Fields(int_Campo).Name & _
vbTab
Next 'int_Campo
str_Linea = Left(str_Linea,Len(str_Linea) - 1)
str_Subrayado = Left(str_Subrayado,Len(str_Subrayado) - 1)
End If
'Los subrayamos
WScript.Echo String(Len(str_Linea), "=")
'Almacenamos el nombre
str_Linea = str_Linea & _
rs_Tabla.Fields(int_Campo).Value & _
vbTab
Next 'int_Campo
Wend
'Creamos el Recordset
Set rs_Tabla = CreateObject("ADODB.Recordset")
Perfecto, ya podemos movernos adelante y atrs con este cursor, agregar, modificar y borrar registros! Va ser
que no... La ltima lnea del cdigo nos mostrar el tipo de cursor abierto por pantalla, que debera haber sido
2, correspondiente a adOpenDynamic, sin embargo mostrar un 3, el correspondiente a adOpenStatic, que
nos permite movernos adelante y atrs en el Recordset, pero no permite actualizaciones, inserciones ni
borrados. Esto es debido a que el
'Establecemos su nombre
ado_Tabla.Name = "MiHoja"
'Creamos el adCurrency
Set ado_Campo = CreateObject("ADOX.Column")
With ado_Campo
.Name = "Moneda"
.Type = adCurrency
End With
'Creamos el adDate
Set ado_Campo = CreateObject("ADOX.Column")
With ado_Campo
.Name = "Fecha"
.Type = adDate
End With
'Creamos el adDouble
Set ado_Campo = CreateObject("ADOX.Column")
With ado_Campo
.Name = "Numerico"
.Type = adDouble
End With
'Creamos el adVarWChar
Set ado_Campo = CreateObject("ADOX.Column")
With ado_Campo
.Name = "Texto"
.Type = adVarWChar
End With
Como podemos ver, es bastante trabajoso, de ah el que yo prefiera usar la potencia de SQL, en concreto la
parte DDL. Al usar DDL los pasos a dar son:
Veamos ahora la creacin del mismo libro de antes usando DDL. La instruccin DDL para la creacin de
tablas es CREATE TABLE, cuya sintaxis es:
1. Booleano: bit.
2. Fecha: datetime.
3. Moneda: money.
4. Numrico: numeric.
5. Texto: varchar.
La mxima precisin es de 15 decimales, que es la mxima precisin de Excel. Aunque el mximo tamao de
contenido de una celda sea de 32 Kbytes, el driver ODBC de Excel slo permite texto de 255 caracteres, a no
ser que sea Excel 2000 o posterior y retoquemos el registro (Knowledge Base 189897); este problema no lo
tiene Jet.
'Definicin del objeto de conexin
Dim ado_Conexion 'As ADODB.Connection
Bastante ms simple que con ADOX verdad? Si se tratara de crear una base de datos Access, sera preferible
ADOX, pues nos permite definir muchas ms propiedades de los campos, tipos de datos, precisiones de los
mismos, etc., pero teniendo en cuenta las limitaciones de ADO al manejar Excel, que estamos viendo a lo
largo de este artculo, es ms que suficiente el uso de sentencias DDL.
INSERT INTO Tabla [(campo1, campo2, ..., campoN)] VALUES (valor1, valor2,
..., valorN)
Como tabla tendremos que poner el nombre de la hoja o rango con nombre. Si insertamos en una hoja, lo har
en la lnea inmediatamente por debajo de la ltima escrita, si se trata de un intervalo con nombre, lo har en la
primera lnea a continuacin de la ltima del rango, es decir, como si aumentara el rango una lnea ms, pero
ojo, si la lnea est ya escrita, se producir el error -2147467259: No se puede expandir el
intervalo con nombre. La sentencia de insercin ser evaluada, esperando encontrar los tipos de datos
adecuados. Cada tipo tiene sus normas:
Dado que Excel interpreta el tipo de datos de las columnas analizando el tipo de los primeros 8
registros, si la tabla est vaca, al no tener datos suficientes para decidir los tipos de datos de las
columnas, lo considerar todo como texto, aun cuando hubieramos creado la tabla con ADODB
estableciendo otro tipo de datos en las columnas. Una vez se tiene al menos un registro con los datos
claramente definidos en su tipo, la insercin la har con el tipo requerido y adems dar error el intentar
insertar un dato de un tipo diferente al de la columna, por ejemplo al intentar escribir texto en una
columna numrica.
Los textos los inserta siempre con una comilla simple por delante; es decir, si ponemos que inserte en
un campo Este texto, en el libro excel aparecer como contenido de la celda 'Este texto.
Si borrramos todos los registros dejando los encabezados, al hacer una nueva insercin se realizar en
la lnea inmediatamente por debajo del ltimo registro que haba, a pesar de estar las lineas superiores
sin nada. Para evitar esto hay que eliminar las lneas, no borrarlas.
Se considerar ltima lnea escrita de una hoja no la ltima de la tabla de la hoja en s, si no la ltima
lnea escrita en la hoja; esto quiere decir que si tuviramos ms de una tabla en una hoja (la tabla propia
de la hoja y una o ms creadas en rangos con nombre), en el caso de escribir en la hoja (no en un rango
con nombre, pues ya vimos que slo se puede escribir en la primera lnea por debajo del rango, si est
vaca), se escribira en la lnea siguiente a la ltima ocupada en cualquiera de las tablas que contenga la
hoja, eso s, en las columnas correspondientes a la tabla en la que se escribe.
Nota: La sintaxis de sentencia INSERT que he puesto ms arriba no es la nica posible, solo se trataba de explicar el ejemplo expuesto.
Es posible insertar de golpe muchos registros basado en una consulta. Para una descripcin ms profunda de INSERT INTO:
Modificacin De Datos
Podemos modificar datos por medio de la instruccin UPDATE de SQL, cuya sintaxis es:
Podemos cambiar uno o varios campos de uno o varios registros. La parte SET se encarga de establecer qu
campos se cambian y qu valores se les ponen y la parte WHERE se encarga de especificar qu registros son
los afectados; si no se especifica parte WHERE, todos los registros son modificados.
No se pueden modificar frmulas (el contenido de la celda empieza por el caracter igual =), pues las frmulas
son de slo lectura.
Borrado De Datos
Esto va ser muy rpido: no se pueden borrar registros, pues se produce el error Este ISAM no admite
la eliminacin de datos de tablas vinculadas. Slo se puede borrar campo por campo, es
decir, vaciar de contenido el registro, aunque, realmente, ste no desaparece, al no haberse eliminado la lnea.
Tampoco se pueden borrar celdas que contengan frmulas de Excel, produciendose el error Operacin no
permitida en este contexto.
Ejemplos
A continuacin pongo dos ejemplos de uso de ADO con libros de Excel. Si los quieres probar, hazlo desde un
equipo que no tenga Excel instalado, ser mas chulo -(|:o)).
Ejemplo 1
Este script permite leer el contenido del libro de Excel que recibe como parmetro sin nombre requerido. El
script volcar en pantalla el contenido de cada hoja. Su sintaxis es:
Siendo
libro (Requerido): Ruta y nombre del libro de Excel (XLS) que se ha de leer.
/S: encabezados (Opcional): Si se pasa este modificador, se considerar que las hojas no contienen
encabezados, y por tanto la primera fila contiene datos; si no se pasa, la primera fila se considerar
como nombre de los campos de la tabla.
/?: ayuda (Opcional): Muestra la ayuda en lnea
'*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
'**
'* leer-xls-con-ado.vbs *
'* *
'* Este script permite leer el contenido del libro de Excel que recibe *
'* como parmetro sin nombre requerido. El script volcar el contenido *
'* de cada hoja. Para leer el libro Excel utiliza ADO, lo que permite *
'* que se puedan leer sus datos en un equipo que no tenga Excel *
Const adSchemaTables = 20
bol_SinEncabezados = False
End If
Call s_Volcar(ado_Recordset)
ado_Recordset.Close
ado_Conexion.Close
Set ado_Recordset = Nothing
Set ado_Conexion = Nothing
Sub s_VolcarDatosTabla(str_Hoja)
Dim ado_Recordset
Next 'int_Campo
str_Linea = Left(str_Linea,Len(str_Linea)-1)
WScript.Echo str_linea
Next 'int_Campo
str_Linea = Left(str_Linea,Len(str_Linea)-1)
WScript.Echo str_linea
str_Linea = ""
ado_Recordset.MoveNext
Loop
ado_Recordset.Close
Set ado_Recordset = Nothing
End Sub
WScript.Quit 0
End If
Else
End If
Sub s_Ayuda(str_Error)
'***********************************************************************
'* Procedimiento: s_Ayuda *
'* Tipo : Sub *
'* Devolucin : *
'* Fecha y Hora : 2008-03-07 17:10:14 *
'* Autor : Fernando Reyes *
'**
'* Propsito : Este procedimiento muestra la ayuda en lnea. *
'* Recibe un parmetro de tipo cadena que si viene *
'* ser mostrado antes de la lnea; pensado para que *
'* se muestre un error que se haya detectado. *
'***********************************************************************
End If
End If
' ado_Conexion.Close
Set ado_Conexion = Nothing
End If
' ado_Recordset.Close
Set ado_Recordset = Nothing
Sub s_Volcar(rs_Consulta)
Next 'int_Campo
str_Linea = Left(str_Linea,Len(str_Linea) - 1)
WScript.Echo str_Linea
str_Linea = ""
Next 'int_Campo
arr_Adjuntos = f_Comprimir(rs_Consulta.Fields("id_informe").Value)
MsgBox str_Adjunto
Next
WScript.Echo str_Linea
str_Linea = ""
rs_Consulta.MoveNext
Wend
End Sub
rs_Consulta.MoveNext
Wend
str_Devolucion = Left(str_Devolucion,Len(str_Devolucion) - 1)
End If
rs_Consulta.Close
Set rs_Consulta = Nothing
f_Cuentas = str_Devolucion
End Function
Function f_Comprimir(id_Informe)
MsgBox str_Comando
rs_Consulta.MoveNext
Wend
End If
rs_Consulta.Close
rs_Consulta.MoveNext
Wend
End If
rs_Consulta.Close
End Function
Ejemplo 2
Por ltimo, presento un ejemplo de uso de un libro de Excel desde VBScript sin necesidad de tener instalada
la aplicacin en el equipo. En concreto desarroll esto para enviar determinados informes a determinadas
Un script que ser el que realice los envos de correos segn los datos que lee del libro de Excel.
Un libro de Excel con los datos de destinatarios, correos, adjuntos, etc.
Informes: hoja con los datos de los informes a enviar. Consta de las columnas:
id_informe (numrico): identificador del informe. Hace de clave primaria de la tabla.
nombre (texto): nombre del informe.
asunto (texto): asunto del correo.
cuerpo (texto): cuerpo del correo.
smtp (texto): URL del servidor SMTP con el que se realizar el envo.
puerto (numrico): puerto TCP del servidor SMTP.
cuenta (texto):cuenta de correo que remite el mensaje.
usuario (texto): nombre de usuario con el que se conecta al servidor SMTP.
clave (texto): contrasea del usuario de conexin.
Ficheros: hoja con los datos correspondientes a los adjuntos de los correos. Consta de las columnas:
id_informe (numrico): identificador del informe. Hace de clave externa a la hoja de informes.
id_fichero (numrico): identificador del fichero en el mensaje. La conjuncin de id_informe e
id_fichero genera la clave primaria de esta hoja.
nombre (texto): ruta y nombre del fichero a adjuntar. Admite caracteres comodn (asterisco,
interrogacin)
archivo (texto): ruta y nombre del archivo ZIP al que se aadir el fichero. De esta manera los
adjuntos sern enviados comprimidos. Para ello es necesario que se instale en el sistema el
ejecutable independiente de 7-Zip, es decir, 7za.exe.
Tres hojas de estrucutra idntica que son Para, CC y CCO. Contienen los datos de los destinatarios en el
campo Para, en el campo con copia y en el campo con copia oculta. Las columnas de las que constan
estas hojas son:
id_informe (numrico): identificador del informe que se enva. Se trata de la clave externa a la
hoja de informes.
destinatario (texto): nombre para mostrar del destinatario.
email (texto): direccin de correo del destinatario.
En el libro he dejado datos de ejemplo que implican que se enven tres informes:
Connection Object
Represents an open connection to a data source.
Remarks
A Connection object represents a unique session with a data source. In the case of a client/server database system, it may be
equivalent to an actual network connection to the server. Depending on the functionality supported by the provider, some
collections, methods, or properties of a Connection object may not be available.
With the collections, methods, and properties of a Connection object, you can do the following:
Configure the connection before opening it with the ConnectionString, ConnectionTimeout, and Mode properties.
ConnectionString is the default property of the Connection object.
Set the CursorLocation property to client to invoke the Microsoft Cursor Service for OLE DB, which supports batch
updates.
Set the default database for the connection with the DefaultDatabase property.
Set the level of isolation for the transactions opened on the connection with the IsolationLevel property.
Specify an OLE DB provider with the Provider property.
Establish, and later break, the physical connection to the data source with the Open and Close methods.
Execute a command on the connection with the Execute method and configure the execution with the
CommandTimeout property.
NoteTo execute a query without using a Command object, pass a query string to the Execute method
of a Connection object. However, a Command object is required when you want to persist the
command text and re-execute it, or use query parameters.
Manage transactions on the open connection, including nested transactions if the provider supports them, with the
BeginTrans, CommitTrans, and RollbackTrans methods and the Attributes property.
Examine errors returned from the data source with the Errors collection.
Read the version from the ADO implementation used with the Version property.
Obtain schema information about your database with the OpenSchema method.
You can create Connection objects independently of any other previously defined object.
You can execute named commands or stored procedures as if they were native methods on a Connection object, as shown
below. When a named command has the same name as that of a stored procedure, invoke the "native method call" on a
Connection object always execute the named command instead of the store procedure.
NoteDo not use this feature (calling a named command or stored procedure as if it were a native method on
the Connection object) in a Microsoft .NET Framework application, because the underlying implementation
of the feature conflicts with the way the .NET Framework interoperates with COM.
To execute a command, give the command a name using the Command object Name property. Set the Command object's
ActiveConnection property to the connection. Then issue a statement where the command name is used as if it were a
method on the Connection object, followed by any parameters, then followed by a Recordset object if any rows are
returned. Set the Recordset properties to customize the resulting Recordset. For example:
To execute a stored procedure, issue a statement where the stored procedure name is used as if it were a method on the
Connection object, followed by any parameters. ADO will make a "best guess" of parameter types. For example:
See Also
Command Object | Errors Collection | Properties Collection | Recordset Object | Appendix A: Providers
2016 Microsoft
Although using this provider is a convenient way to access data through ODBC data sources, it is possible to obtain better
performance and reliability by using a native provider. For more information about other OLE DB providers written to access
specific data stores, see Microsoft OLE DB Providers Overview, visit the Microsoft Data Access and Storage Developer Center,
or contact your software vendor.
Security Considerations
Review OLE DB Security Best Practices for information about security with OLE DB.
Version Compliance
Supported Platforms
Data Types
Query-Based Updates
Known Limitations
2016 Microsoft
If you are a scripter with a modest understanding of database connectivity, you will find ADO's command syntax
uncomplicated and easy-to-use. If you are an experienced developer you will appreciate the scalable, high-performance
access ADO provides to a variety of data sources.
For more information about ADO, visit the Data Access Technologies Web site on MSDN.
The following table lists OLE DB connection strings for several common data sources:
To provide for backward compatibility, the OLE DB Provider for ODBC supports ODBC connection string syntax. The
following table lists commonly used ODBC connection strings:
Note:
Connection strings that use a UNC path to refer to a data source located on a remote computer can pose a potential
security issue. To prevent unauthorized access of your data source, create a Windows account for computers requiring
access to the data and then apply appropriate NTFS permissions to the data source.
ASP supports shared file databases (Access or FoxPro) as valid data sources. Although some ASP examplecodeuse a
shared file database, it is recommended that these types of database engines be used only for development purposes or
limited deployment scenarios. Shared file databases may not be as well suited as client-server databases for very
high-demand, production-quality Web applications.
If you are developing an ASP database application intended to connect to a remote SQL Server database you should also
be aware of the following issues:
You can choose between the TCP/IP Sockets and Named Pipes methods for accessing a remote SQL Server database. With
Named Pipes, database clients must be authenticated by Windows before establishing a connection, raising the possibility
that a remote computer running named pipes might deny access to a user who has the appropriate SQL Server access
credentials, but does not have a Windows user account on that computer. Alternatively, connections using TCP/IP Sockets
connect directly to the database server, without connecting through an intermediary computer - as is the case with Named
Pipes. And because connections made with TCP/IP Sockets connect directly to the database server, users can gain access
through SQL Server authentication, rather than Windows authentication.
If the connection scheme for accessing SQL Server is not set correctly, users viewing your database application may receive
an ODBC 80004005 error message. To correct this situation, try using a local named pipe connection instead of a network
named pipe connection if SQL Server is running on the same computer as IIS. Windows Server2003 family security rules
will not be enforced because the pipe is a local connection rather than a network connection, which can be impersonated
by the anonymous user account. Also, in the SQL Server connection string (either in the Global.asa file or in a page-level
script), change the parameter SERVER=server name to SERVER=(local). The keyword (local) is a special parameter
recognized by the SQL Server ODBC driver. If this solution does not work, then try to use a non-authenticated protocol
between IIS and SQL Server, such as TCP/IP sockets. This protocol will work when SQL Server is running locally or on a
remote computer.
Note:
If you use SQL Server's Integrated or Mixed security features, and the SQL Server database resides on a remote server, you
will not be able to use integrated Windows authentication. Specifically, you cannot forward integrated Windows
authentication credentials to the remote computer. This means that you may have to use Basic authentication, which relies
on the user to provide user name and password information.
For more information about these issues, see the Microsoft Product Support Services Web site.
To establish a database connection, you first create an instance of the Connection object. For example, the following script
instantiates the Connection object and proceeds to open a connection:
<%
'Create a connection object.
Set cnn = Server.CreateObject("ADODB.Connection")
'Open a connection using the OLE DB connection string.
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MarketData
\ProjectedSales.mdb"
%>
Note:
The connection string does not contain spaces before or after the equal sign (=).
In this case, the Connection object's Open method refers to the connection string.
The following script uses the Execute method to issue a query in the form of a SQL INSERT command, which inserts data
into a specific database table. In this case, the script block inserts the name Jose Lugo into a database table named
Customers.
<%
'Define the OLE DB connection string.
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data
\Employees.mdb"
Note that two parameters are specified in the statement used to execute the query: adCmdText and
adExecuteNoRecords. The optional adCmdText parameter specifies the type of command, indicating that the provider
should evaluate the query statement (in this case, a SQL query) as a textual definition of a command. The
adExecuteNoRecords parameter instructs ADO to not create a set of data records if there are no results returned to the
application. This parameter works only with command types defined as a text definition, such as SQL queries, or stored
database procedures. Although the adCmdText and adExecuteNoRecords parameters are optional, you should specify
theses parameters when using the Execute method to improve the performance of your data application.
Important Note:
ADO parameters, such as adCmdText, need to be defined before you can use them in a script. A convenient way to
define parameters is to use a component type library, which is a file containing definitions for all ADO parameters. To
implement a component type library, it must first be declared. Add the following the <METADATA> tag to your .asp file
or Global.asa file to declare the ADO type library:
For details about implementing component type libraries, see the Using Constants section of the Using Variables and
Constants topic.
In addition to the SQL INSERT command, you can use the SQL UPDATE and , you can use the SQL UPDATE and DELETE
commands to change and remove database information.
With the SQL UPDATE command you can change the values of items in a database table. The following script uses the
UPDATE command to change the Customers table's FirstName fields to Jeff for every LastName field containing the last
name Smith.
<%
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data\Employees.mdb"
cnn.Execute "UPDATE Customers SET FirstName = 'Jeff' WHERE LastName = 'Smith'
",,adCmdText + adExecuteNoRecords
%>
To remove specific records from a database table, use the SQL DELETE command. The following script removes all rows
from the Customers table where the last name is Smith:
<%
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data\Employees.mdb"
cnn.Execute "DELETE FROM Customers WHERE LastName = 'Smith'",,adCmdText +
adExecuteNoRecords
%>
Note:
You must be careful when using the SQL DELETE command. A DELETE command without an accompanying WHERE
clause will delete all rows from a table. Be sure to include a SQL WHERE clause, which specifies the exact rows to be
deleted.
<%
'Establish a connection with data source.
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data
\Employees.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
Do Until rstCustomers.EOF
Response.Write objFirstName & " " & objLastName & "<BR>"
rstCustomers.MoveNext
Loop
%>
Note that in the previous example, the Connection object established the database connection, and the Recordset object
used the same connection to retrieve results from the database. This method is advantageous when you need to precisely
configure the way in which the link with the database is established. For example, if you needed to specify the time delay
before a connection attempt aborts, you would need to use the Connection object to set this property. However, if you
just wanted to establish a connection using ADO's default connection properties, you could use Recordset object's Open
method to establish a link:
<%
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data
\Employees.mdb"
strSQL = "SELECT FirstName, LastName FROM Customers WHERE LastName = 'Smith' "
Set rstCustomers = Server.CreateObject("ADODB.Recordset")
When you establish a connection using the Recordset object's Open method to establish a connection, you are implicitly
using the Connection object to secure the link. For more information, see Microsoft ActiveX Data Objects (ADO)Help
available from the Microsoft Universal Data Access Web site.
Note:
To significantly improve the performance of your ASP database applications, consider caching the recordset in
Application state. For more information, see Caching Data.
It is often useful to count the number of records returned in a recordset. The Open method of the Recordset object
enables you to specify an optional cursor parameter that determines how the underlying provider retrieves and navigates
the recordset. By adding the adOpenKeyset cursor parameter to the statement used to execute the query, you enable the
client application to fully navigate the recordset. As a result, the application can use the RecordCount property to
accurately count the number of records in the recordset. See the following example:
<%
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "SELECT * FROM NewOrders", "Provider=Microsoft.Jet.OLEDB.3.51;Data
Source='C:\CustomerOrders\Orders.mdb'", adOpenKeyset, adLockOptimistic, adCmdText
Do Until rs.EOF
Response.Write rs("CustomerFirstName") & " " & rs("CustomerLastName") & "<BR>"
Response.Write rs("AccountNumber") & "<BR>"
Response.Write rs("Quantity") & "<BR>"
Response.Write rs("DeliveryDate") & "<BR><BR>"
rs.MoveNext
Loop
Else
Response.Write "There are less than " & rs.RecordCount & " new orders."
End If
rs.Close
%>
The Command object's Parameters collection saves you the trouble of reconstructing your query each time you want to
reissue your query. For example, if you need to regularly update supply and cost information in your Web-based inventory
system, you can predefine your query in the following way:
<%
'Open a connection using Connection object. Notice that the Command object
'does not have an Open method for establishing a connection.
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data
\Inventory.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
Important Note:
ADO parameters, such as adCmdText, are simply variables, this means that before using an ADO parameter in a data
access script you need to define its value. Since ADO uses a large number of parameters, it is easier to define
parameters by means of a component type library, a file containing definitions for every ADO parameter and constant.
For details about implementing ADO's type library, see the Using Constants section of the Using Variables and
Constants topic.
In the previous example, you will note that the script repeatedly constructs and reissues a SQL query with different values,
without having to redefine and resend the query to the database source. Compiling your queries with the Command
object also offers you the advantage of avoiding problems that can arise from concatenating strings and variables to form
SQL queries. In particular, by using the Command object's Parameter collection, you can avoid problems related to
defining certain types of string, date, and time variables. For example, SQL query values containing apostrophes (') can
cause a query to fail:
Note that the last name O'Hara contains an apostrophe, which conflicts with the apostrophes used to denote data in the
SQL VALUES keyword. By binding the query value as a Command object parameter, you avoid this type of problem.
<%
'Open a connection using Connection object. The Command object
'does not have an Open method for establishing a connection.
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\CompanyCatalog
\Seeds.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
For more information about forms and using the ASP Request object, see Processing User Input.
With the Connection object's ConnectionTimeout you can limit the amount of time that your application waits before
abandoning a connection attempt and issuing an error message. For example, the following script sets the
ConnectionTimeout property to wait twenty seconds before cancelling the connection attempt:
Note:
Before incorporating the ConnectionTimeout property into your database applications, make sure that your
connection provider and data source support this property.
Pooling Connections
Connection pooling enables your Web application to use a connection from a pool, or reservoir of free connections that do
not need to be reestablished. After a connection has been created and placed in a pool, your application reuses that
connection without having to perform the connection process. This can result in significant performance gains, especially if
your application connects over a network or repeatedly connects and disconnects. In addition, a pooled connection can be
used repeatedly by multiple applications.
You can selectively set the CPTimeout property to enable connection pooling for a specific ODBC database driver by
creating a registry key with the following settings:
\HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\driver-name\CPTimeout = timeout
(REG_SZ, units are in seconds)
For example, the following key sets the connection pool timeout to 180 seconds (3 minutes) for the SQL Server driver.
Note:
By default, your Web server activates connection pooling for SQL Server by setting CPTimeout to 60 seconds.
Then in each ASP file that accesses the database, you can write
to create an instance of the connection object for the page, and use the script
cnn.Open Application("ConnectionString")
to open the connection. At the end of the page, you close the connection with
cnn.Close
In the case of an individual user who needs to reuse a connection across multiple Web pages, you may find it more
advantageous to use the Session object rather than the Application object for storing the connection string.
Closing Connections
To make the best use of connection pooling, explicitly close database connections as soon as possible. By default, a
connection terminates after your script finishes execution. However, by explicitly closing a connection in your script after it
is no longer needed, you reduce demand on the database server and make the connection available to other users.
You can use Connection object's Close method to explicitly terminate a connection between the Connection object and
the database. The following script opens and closes a connection:
<%
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data
\Inventory.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
cnn.Close
%>
2016 Microsoft
Recordset Object
Represents the entire set of records from a base table or the results of an executed command. At any time, the Recordset
object refers to only a single record within the set as the current record.
Remarks
You use Recordset objects to manipulate data from a provider. When you use ADO, you manipulate data almost entirely
using Recordset objects. All Recordset objects consist of records (rows) and fields (columns). Depending on the functionality
supported by the provider, some Recordset methods or properties may not be available.
ADODB.Recordset is the ProgID that should be used to create a Recordset object. Existing applications that reference the
outdated ADOR.Recordset ProgID will continue to work without recompiling, but new development should reference
ADODB.Recordset.
Dynamic cursor allows you to view additions, changes, and deletions by other users; allows all types of movement
through the Recordset that doesn't rely on bookmarks; and allows bookmarks if the provider supports them.
Keyset cursor behaves like a dynamic cursor, except that it prevents you from seeing records that other users add,
and prevents access to records that other users delete. Data changes by other users will still be visible. It always
supports bookmarks and therefore allows all types of movement through the Recordset.
Static cursor provides a static copy of a set of records for you to use to find data or generate reports; always allows
bookmarks and therefore allows all types of movement through the Recordset. Additions, changes, or deletions by
other users will not be visible. This is the only type of cursor allowed when you open a client-side Recordset object.
Forward-only cursor allows you to only scroll forward through the Recordset. Additions, changes, or deletions by
other users will not be visible. This improves performance in situations where you need to make only a single pass
through a Recordset.
Set the CursorType property prior to opening the Recordset to choose the cursor type, or pass a CursorType argument with
the Open method. Some providers don't support all cursor types. Check the documentation for the provider. If you don't
specify a cursor type, ADO opens a forward-only cursor by default.
If the CursorLocation property is set to adUseClient to open a Recordset, the UnderlyingValue property on Field objects is
not available in the returned Recordset object. When used with some providers (such as the Microsoft ODBC Provider for
OLE DB in conjunction with Microsoft SQL Server), you can create Recordset objects independently of a previously defined
Connection object by passing a connection string with the Open method. ADO still creates a Connection object, but it
doesn't assign that object to an object variable. However, if you are opening multiple Recordset objects over the same
connection, you should explicitly create and open a Connection object; this assigns the Connection object to an object
variable. If you do not use this object variable when opening your Recordset objects, ADO creates a new Connection object
for each new Recordset, even if you pass the same connection string.
When you open a Recordset, the current record is positioned to the first record (if any) and the BOF and EOF properties are
set to False. If there are no records, the BOF and EOF property settings are True.
You can use the MoveFirst, MoveLast, MoveNext, and MovePrevious methods; the Move method; and the AbsolutePosition,
AbsolutePage, and Filter properties to reposition the current record, assuming the provider supports the relevant
functionality. Forward-only Recordset objects support only the MoveNext method. When you use the Move methods to visit
each record (or enumerate the Recordset), you can use the BOF and EOF properties to determine if you've moved beyond
the beginning or end of the Recordset.
Before using any functionality of a Recordset object, you must call the Supports method on the object to verify that the
functionality is supported or available. You must not use the functionality when the Supports method returns false. For
example, you can use the MovePrevious method only if Recordset.Supports(adMovePrevious) returns true.
Otherwise, you will get an error, because the Recordset object might have been closed and the functionality rendered
unavailable on the instance. If a feature you are interested in is not supported, Supports will return false as well. In this case,
you should avoid calling the corresponding property or method on the Recrodset object.
Recordset objects can support two types of updating: immediate and batched. In immediate updating, all changes to data
are written immediately to the underlying data source once you call the Update method. You can also pass arrays of values as
parameters with the AddNew and Update methods and simultaneously update several fields in a record.
If a provider supports batch updating, you can have the provider cache changes to more than one record and then transmit
them in a single call to the database with the UpdateBatch method. This applies to changes made with the AddNew, Update,
and Delete methods. After you call the UpdateBatch method, you can use the Status property to check for any data conflicts
in order to resolve them.
NoteTo execute a query without using a Command object, pass a query string to the Open method of a
Recordset object. However, a Command object is required when you want to persist the command text and
re-execute it, or use query parameters.
The Fields collection is the default member of the Recordset object. As a result, the following two code statements are
equivalent.
When a Recordset object is passed across processes, only the rowset values are marshalled, and the properties of the
Recordset object are ignored. During unmarshalling, the rowset is unpacked into a newly created Recordset object, which
also sets its properties to the default values.
See Also
Connection Object | Fields Collection | Properties Collection | Appendix A: Providers
2016 Microsoft