Imprimir página | Cerrar ventana

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 ...  LOL

¿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 Wink

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 ... Tongue


-------------
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 ...  LOL

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 Wink


-------------
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 LOL


-------------
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” LOL, 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.



Imprimir página | Cerrar ventana