como grabar una matriz en una tabla
Impreso de: Foro de Access y VBA
Categoría: Access y VBA
Nombre del foro: Access y VBA
Descripción del foro: Foro de programacion en Access (Con código y sin código)
URL: http://www.mvp-access.com/foro/forum_posts.asp?TID=85128
Fecha de impresión: 26/Marzo/2026 a las 17:28
Tema: como grabar una matriz en una tabla
Publicado por: kkodalton
Asunto: como grabar una matriz en una tabla
Fecha de publicación: 05/Abril/2020 a las 10:25
Hola
Me gustaria saber como puedo grabar una matriz unidimensional en una tabla de la manera mas eficiente (50), los 50 campos de la matriz se corresponde con los 50 de la tabla a guardar.
En realidad mi matriz es bidimensional , però he pensado que mejor ir grabando registro a registro A(500000,50)
De Vb no se mucho mi pregunta es , he de utilitzar para grabar cada campo el .Update?
o por medio del insert into tabla ... como lo hago para los 50 campos ?
Espero que entendais mi problema y muchas gracias
|
Respuestas:
Publicado por: Mihura
Fecha de publicación: 05/Abril/2020 a las 10:45
La cuestión es si has sido 'astuto' al crear la tabla y los nombres de campos incluyen un número de orden, o el nombre de cada campo es de su padre y de su madre ... 
¿Como tienes definida la tabla?
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: kkodalton
Fecha de publicación: 05/Abril/2020 a las 12:29
|
Si , los campos son mes_año Estos serian los campos : id usuario 012010 022010 032010 etc.
|
Publicado por: Mihura
Fecha de publicación: 05/Abril/2020 a las 13:00
|
Te recomendaría que en los nombres de campos no uses blancos y que comiencen al menos con una letra, te evitará muchos problemas en su uso. - yo llamaría a los campos IdUsuario, C012010, C022010, ...
¿ Cómo es la correspondencia de campos con los valores de la tabla ?
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: Dabellaso
Fecha de publicación: 05/Abril/2020 a las 15:59
|
Quizás buscas algo así?
NOTA: mtz es la matriz bidimensional
dim i as Long, x as Long
For i = LBound(mtz, 1) To UBound(mtz, 1) 'Para recorrer la primera dimensión For x = LBound(mtz, 2) To UBound(mtz, 2) 'Para recorrer la segunda dimensión CurrentDb.Execute ("INSERT INTO MiTabla (MiCampo1, MiCampo2) VALUES ('" & _ mtz(i, x) & "','" & mtz(i, x) & "');") Next x Next i
Pero como bien dice Mihura, es importante saber cual es tu situación específica. Sera difícil aplicarlo a tu caso sin tener claro el tipo de campo (Si son de texto o numéricos, por el tema de las comillas simples), de si la tabla tiene algún campo requerido, que los datos cumplan con las validaciones, etc.
De todos modos puedes consultar, ya que tienes al menos dos modos de hacerlo según tu situación https://docs.microsoft.com/es-es/office/client-developer/access/desktop-database-reference/insert-into-statement-microsoft-access-sql" rel="nofollow - https://docs.microsoft.com/es-es/office/client-developer/access/desktop-database-reference/insert-into-statement-microsoft-access-sql
------------- El saber no ocupa lugar, sólo tiempo
|
Publicado por: kkodalton
Fecha de publicación: 05/Abril/2020 a las 18:46
|
hola de nuevo y gracias por contestar
A ver, imaginar que tengo definida una matriz con estos valores:
Se que no se representa asi en acces, pero es para acabar antes:
matriz unidimensional :mtz(20)
Valores mtz: (540,457,0,7688,7679.4445.... ,456)
Lbound y Ubound acabo de mirar que significa, pero la verdad no lo entiendo mucho. Pero yo querria añadir todos los valores de la matriz, en una tabla, con lo que lbound no creo me sirva.
Si utilizo el metodo "insert into mitabla ( aqui tengo que espeficicar todos los campos??
No existe una manera de decir insertar todos los datos de esta matriz a esta tabla????? la matriz hace referencia a los mismos campos ordenados que representa la tabla, asi por ejemplo el valor 540 quiero que se guarde en el campo1 de la tabla, 457 es el segundo, y asi ...
Espero no haberos liado mas
|
Publicado por: Mihura
Fecha de publicación: 05/Abril/2020 a las 18:58
|
¿Podrías cambiar los nombres de los campos de la tabla a ... ?
IdUsuario Campo01 Campo02 Campo03 . . Campo50
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: Dabellaso
Fecha de publicación: 05/Abril/2020 a las 19:43
Creo entender que si la matriz tiene 50 valores, deber introducir cada valor en un campo diferente, es decir, tienes 50 campos, correcto? y que la matriz, es unidimensional
Prueba a obtener los nombres de cada campo en cada vuelta del bucle, y de ese modo cada campo tendrá el valor que le corresponde al item de la matriz en el mismo orden
Quizás algo así:
Dim i As Long, tabla As DAO.TableDef
Set tabla = CurrentDb.TableDefs("MiTabla")
For i = LBound(mtz) To UBound(mtz) 'Para recorrer los datos de la matriz de valores
x = x + 1 'x+1 porque al ser una colección Fields empieza en uno, dejarlo en cero produciría error CurrentDb.Execute ("INSERT INTO MiTabla ( " & tabla.Fields(x).Name & ") VALUES ('" & mtz(i) & "');") Next i
NOTA: i= LBound(Matriz) significa que el bucle empezara con el ítem más bajo de la matriz, es decir, desde el principio i= UBound(Matriz) significa que el bucle se repetirá hasta encontrar el ítem más alto en la matriz, es decir, hasta el final
Es importante, que la cantidad de valores en la matriz sea la misma o menos que campos en la tabla, de otro modo generará error por no encontrar el campo
Prueba a ver si te sirve 
Edito: eso te creará tantos registros como valores tenga la matriz, si solo quieres un registro con todos los campos rellenos, hay que abordarlo de manera diferente. Voy a darle una vuelta y luego nos cuentas porque no sé donde quedo la matriz bidimensional que decías al principio
------------- El saber no ocupa lugar, sólo tiempo
|
Publicado por: Dabellaso
Fecha de publicación: 05/Abril/2020 a las 20:03
|
Quizás esto te sirva mejor:
Dim i As Long Dim dbs As DAO.Database Dim tabla As DAO.TableDef Dim campo As DAO.Field Dim strListaCampos As String Dim strListaValores As String
Set dbs = CurrentDb Set tabla = dbs.TableDefs("MiTabla") For Each campo In tabla.Fields 'Para recorrer los campos existentes en la tabla strListaCampos = strListaCampos & IIf(strListaCampos = "", "", ",") & campo.Name Next campo For i = LBound(mtz) To UBound(mtz) 'Para recorrer los datos de la matriz de valores strListaValores =strListaValores & IIf(strListaValores = "", "", ",") & "'" & CStr(mtz(i)) & "'" Next i
CurrentDb.Execute ("INSERT INTO MiTabla (" & strListaCampos & ") VALUES (" & strListaValores & ");")
Esto creará un sólo registro, pero del mismo modo, la cantidad de campos y la cantidad de valores deben ser iguales
------------- El saber no ocupa lugar, sólo tiempo
|
Publicado por: kkodalton
Fecha de publicación: 05/Abril/2020 a las 22:19
|
un millon de gracias, mañana lo pruebo
|
Publicado por: guarracuco
Fecha de publicación: 07/Abril/2020 a las 14:36
|
Para simplificar bastante el uso de bucles, podrías convertir a cadena de caracteres, cada línea del arreglo, usando la instrucción Join. Más o menos algo asi: For i=0 to ubound(arreglo) StrSql=join(arreglo(i), ",") Currentdb.execute "insert into Tutabla " . StrSql ... ...
|
Publicado por: Mihura
Fecha de publicación: 07/Abril/2020 a las 15:46
|
Matriz bidimensional A(500000, 50)
Si hacemos un INSERT por cada datome salen veinticinco millones de posibles inserciones ...
Supongo que cada registro de la tabla tiene 50 campos ... y sigo esperando la repuesta de si se pueden cambiar los nombres de los campos ... 
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: guarracuco
Fecha de publicación: 07/Abril/2020 a las 16:45
|
Mi idea es ejecutar el Insert por cada línea del arreglo. Que mi código no esté completo, no lo dudo. Lo escribí desde el móvil a la ligera.
Saludos.
|
Publicado por: Mihura
Fecha de publicación: 07/Abril/2020 a las 16:49
Nunca un código esta terminado ... 
Yo lo digo porque en este caso, con ese número de registros mejor con un recordset, te ahorras los tiempos de cierre/apertura de cada SQL.
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: Dabellaso
Fecha de publicación: 07/Abril/2020 a las 19:40
|
Efectivamenete puede evitar el bucle " For i = .... To .... "
y usar, " VariableTexto = Join(mtz,",") " (sin el ítem de la matriz)
Pero como dice Mihura usar INSERTSQL en cada vuelta de bucle al recorrer una matriz bidimensional generará una barbaridad de registros.
El último código que posteé sólo crea un registro pero claro, usando una matriz unidimensional que yo entiendo que tiene 50 valores , para almacenar en 50 campos. No se de donde sacará el resto de registros.
La opción del Recordset también me gusta, pero sigo si saber si tiene una matriz unidimensional ,o una bidimensional.
Esperemos la opinión del intersado y si Mihura tiene la bondad, me gustaría saber como enfoca él la solución, por el tema del cambio de nombre de los campos. Así puedo practicar con las lecciones de uno de los grandes maestros del foro
Saludos
Edito para corregir el nombre de Mihura, que lo escribí mal 
------------- El saber no ocupa lugar, sólo tiempo
|
Publicado por: 01loko
Fecha de publicación: 07/Abril/2020 a las 19:51
|
Yo (que no suelo usar matrices, principalmente por falta e conocimientos) en una ocasion y con 62 campos, lo que hice fue crear una tabla con el nombre de los campos la recorria a la vez que rellenaba su valor desde, en ese caso, un fichero texto.
si os interesa, tengo por algun lado el codigo usado
------------- Recordar de que soy nuevo y estoy aprendiendo.
|
Publicado por: guarracuco
Fecha de publicación: 07/Abril/2020 a las 21:39
Se puede recorrer una matriz bidimensional, sin necesidad de posarte en cada columna, solo tomando la línea completa.
|
Publicado por: Dabellaso
Fecha de publicación: 07/Abril/2020 a las 22:22
|
Leyendo a guarracuco, se me ocurre que, si como dice kkodlton al inicio, su matriz bidimensiona al ser A(500000,50), indica que son 500000 registros, con 50 valores (para 50 campos).
En ese caso atendiendo a guarracuco, sólo tendríamos que recorrer la dimensión de los registros, para obtener, tanto los registros como los datos.
En cada vuelta de cada registro, un For i obtiene los valores de los campos para ese registro.
Dim i As Long Dim x As Long Dim dbs As DAO.Database Dim tabla As DAO.TableDef Dim campo As DAO.Field Dim strListaCampos As String Dim strListaValores As String
Set dbs = CurrentDb Set tabla = dbs.TableDefs("MiTabla") For Each campo In tabla.Fields 'Para recorrer los campos existentes en la tabla strListaCampos = strListaCampos & IIf(strListaCampos = "", "", ",") & campo.Name Next campo For x = LBound(mtz, 1) To UBound(mtz, 1) 'Si la matriz es de la forma (50000,50) recorreremos los 50000 ítems que supongo serán los registros ' strListaValores = Join(mtz, ",") 'No uso Join por que sólo funciona con matrices unidimensionales 'no conozco modo de indicarle la dimension de la que queremos que tome los valores a unir
For i = LBound(mtz, 2) To UBound(mtz, 2) 'Para recorrer la dimensión núm.2 (La de los valores, que según la matriz (50000,50) serán 50 vueltas) ' De este modo obtenemos los 50 valores de los 50 campos del registro actual (x) strListaValores = strListaValores & IIf(strListaValores = "", "", ",") & "'" & CStr(mtz(x, i)) & "'" Next i i = 0 'reiniciamos i, para la próxima vuelta de x 'En este punto, a cada vuelta de i (A cada registro de los 50000, ya tendremos los 50 nuevos valores para cada campo de cada registro) 'Creamos el registro CurrentDb.Execute ("INSERT INTO MiTabla (" & strListaCampos & ") VALUES (" & strListaValores & ");")
Next x
|
Que os parece? Si es eso intentare leer mejor la pregunta la próxima vez antes de responder 
------------- El saber no ocupa lugar, sólo tiempo
|
Publicado por: kkodalton
Fecha de publicación: 08/Abril/2020 a las 07:51
Hola Todavia no he tenido tiempo de mirarme el primero ,y ya tengo otro Gracias
|
Publicado por: kkodalton
Fecha de publicación: 08/Abril/2020 a las 08:56
|
Hola de nuevo
Gracias a todos, empiezo a tener mucha información y ya no se con cual me quedare, lo he de probar. De hecho todavía no tengo hecha ni la matriz, pero me encontraba con ese primer escollo que no sabia como hacerlo.
La tabla que necesito crear no depende de ningun formulario con lo cual los nombres de los campos los puedo cambiar. Mihura me recomiendas que los nombres no empiecen por un numero y así me evitare muchos problemas, esto ya me ha pasado y lo he tenido que cambiar, pero podrías explicarme el motivo? Podria poner los nombres de los campos como tu digas y después de hacer todo el proceso para grabarla nueva tabla renombrarlos para que sean mas claros para mi, verdad?
Guarracuco, me podrias explicar que significa y que haría esto: Yo creia que el join solo existia en una consulta sql ...
For i=0 to ubound(arreglo) StrSql=join(arreglo(i), ",") Currentdb.execute "insert into Tutabla " . StrSql
De hecho mi tabla inicial tiene n registros , donde un mismo usuario tiene m registros dentro de esa tabla. Mi intención es crear una nueva tabla de referencias cruzadas, tipo graella. Si en la tabla inicial tuviera ya los valores de los 50 campos, esta claro que haciendo una tabla de referencias cruzadas solucionaria el problema, pero hay campos vacíos que los tengo antes que rellenar, de hecho para los campos vacíos los relleno con el valor anterior del campo anterior. Por ese motivo había pensado en crear una matriz y así cuando ya halla introducido todos los valores en una matriz unidimensional grabar el resultado en una tabla.
Espero haberos aclarado más la situación y muchísimas gracias por todo.
|
Publicado por: Mihura
Fecha de publicación: 08/Abril/2020 a las 09:28
“si Mihura tiene la bondad”  , por cierto al principio de los tiempos era sin la h, pero esta me la incluyó un profe de literatura … pero bueno eso es otra historia.
El no poner números por delante (o blancos entremedias, o caracteres especiales) es que VBA no puede referenciar esos campos directamente (hay que encerrarlos entre corchetes), en los formularios lo mismo, etc … es decir, te creas muuuuucho trabajo gratis, … mejor que no.
Cuando se hace una instrucción SQL, ya sea INSERT INTO, SELECT, DELETE, …. Access realiza una apertura de la tabla (recordset, colección de datos) que va a tratar, el proceso que hemos pedido y un cierre de la misma. Si lo tratamos con un recordset hacemos los mismo: una apertura, el proceso y un cierre del mismo. - si tratamos un registro los procesos son los mismos y los tiempos de ejecución son los mismos, - pero sin tratamos muchos registros la cosa cambia, supongamos los 50.000 de los que hablamos en el hilo, si lo hacemos con SQL hay 50.000 aperturas, 50.000 inserciones de registro y 50.000 cierres, en cambio con un recordset hay una apertura, 50.000 inserciones y un cierre Se nota y mucho.
El proceso con recordset (esquemático y sin comprobar) sería:
Dim Rs as DAO.Recordset
Set Rs = Currentdb.OpenRecordset(“Mitabla”,,dbappendonly) For i = 1 to 50.000 Rs.Addnew Rs!Campo = … … Rs.Update Next Rs.Close
|
En cuanto a la definición de campos me gustaría que nos dijeses que es lo que quieres guardar y que es lo que quieres obtener, … por lo que ‘entreveo’ son datos anuales (desglosados mes a mes), ¿es correcto? ¿son 50 campos ahora, pero que serán 60 dentro de tres meses? ¿serán fijos? … me falta información para seguir adelante con el diseño
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: kkodalton
Fecha de publicación: 08/Abril/2020 a las 11:54
Hola
Si Mihura , son datos anuales desglosados mes a mes. Seran fijos o no? yo diria que puede ser las dos cosas. Es mas rapido para mi que no sean fijos, asi ejecuto y tengo la tabla actualitzada. Tambien podria hacer que a partir de una primera tabla crear una nueva, no se. Este ultimo proceso que has añadido, me gusta a medias.. porque eso significa que he de ir nombrando los 50 campos?, por eso pense en la solucion de la matriz
|
Publicado por: Mihura
Fecha de publicación: 08/Abril/2020 a las 13:00
|
Si son datos anuales yo me crearía una tabla con el siguiente formato:
TDatos: Id -> autonumerico Codigo -> ¿String? ¿Numerico?. Codigo que te identifique el tipo dato que vas a guardar Ano -> Long Mes01 -> Double (enero) Mes02 -> Double (febrero) .. Mes12 -> Double (diciembre)
El tratamiento ya depende de cómo lo vayas a mostrar en el formulario/informe.
Para pasar los datos a esa matriz basta con un bucle:
for i = 1 to 12 Matriz(i) = Rs("Mes" & format(i, "00")) Next
Y al contrario para pasar de la matriz al campo del recordset.
Esto mismo valdría para pasar campos con un formulario, suponiendo que los campos se llamen igual: Forms("MiFormulario").Controls("Mes" & format(i, "00")) = Rs("Mes" & format(i, "00")) o: Me.Controls("Mes" & format(i, "00")) = Rs("Mes" & format(i, "00"))
Otra opción de diseño sería:
TDatos: Id -> autonumerico Codigo -> ¿String? ¿Numerico?. Codigo que te identifique el tipo dato que vas a guardar Ano -> Long Datos -> memo
En el campo Datos se guardarían todos los datos que se necesiten separados por un separador (valga la redundancia) -yo uso la pleca |-, entonces al leer obtienes los datos con un simple split: Matriz = Split(Datos, "|")
y lo guardas con un Join: Rs("Datos") = Join(Matriz, "|")
------------- Jesús Mansilla Castells. Saludos desde Móstoles.
http://www.accessaplicaciones.com" rel="nofollow - Access Aplicaciones http://www.tecsys.es" rel="nofollow - Tecsys.es
|
Publicado por: kkodalton
Fecha de publicación: 17/Abril/2020 a las 10:51
Hola de nuevo
Intente hacerlo con matrices per no me salia, por lo que al final opte por hacerlo con 2 recordset, uno para coger los datos y otro para grabar en la tabla final.
Respecto a los nombres de los campos que me insistiais mucho en que incluyeran un orden, yo en el procedimiento no los he utilizado, en su lugar para referirme a ellos añadia el valor correspondiente en la posicion deseada (campo deseado) , utilizando este formato:
rs1.Fields(x).Value
La tabla resultante ha sido de 33 campos con 400.000 registros, y ejecutarlo solo ha tardado 4 minutos, con lo cual creo que debe ser eficiente.
Quiero añadir que gracias a vuestros comentarios se me ha encendido la luz y he podido acabar el proyecto.
Ahora que me ha salido , me siento muy satisfecho.
|
|