Bucle en módulo

Dudas sobre código
Dayban
Nivel 5
Mensajes: 159
Registrado: Mié Sep 20, 2017 7:08 am

Bucle en módulo

Mensajepor Dayban » Jue Jun 23, 2022 2:06 pm

Buenas tardes a tod@s!!

Tengo un tema en mente y no sé si es posible o cómo hacerlo del todo.
El tema es que tengo un módulo que por los cálculos y registros que mueve se vuelve muy lento, normalmente me deja a access en "no responde". No sé si es buena idea, pero había pensado en que haga el proceso de poco a poco, y ahí está mi duda:
- Es mejor que arranque el módulo desde X punto con el evento "Al cronometro", o puedo programar dicho módulo con algun tipo de pausa?
- Tampoco no sé con la primera opción si pongo un tiempo muy corto, si me puedo encontrar con que el primer arranque no ha acabado y de algun error por intentar arrancar de nuevo. Esto podría pasar o access hasta que no ha acabado no deja arrancarlo de nuevo?
A ver si alguien me puede decir algo....
Cómo siempre, muchísimas gracias.

pitxiku
VIP
Reto02
Mensajes: 585
Registrado: Sab Sep 30, 2017 6:23 pm

Re: Bucle en módulo

Mensajepor pitxiku » Jue Jun 23, 2022 2:45 pm

Entiendo que el código funciona bien, pero la ejecución dura tanto tiempo que no se sabe si se ha colgado Access. Si es el caso, puedes intercalar dentro de ese procedimiento las instrucciones DoEvents necesarias para devolver temporalmente el control y que se actualice Access, la pantalla, Windows haga otras cosas,...

- https://support.microsoft.com/es-es/off ... 3d4c2575b0

Dayban
Nivel 5
Mensajes: 159
Registrado: Mié Sep 20, 2017 7:08 am

Re: Bucle en módulo

Mensajepor Dayban » Jue Jun 23, 2022 10:25 pm

Perdoname, pero no acabo de ver como usarlo.... :oops:

pitxiku
VIP
Reto02
Mensajes: 585
Registrado: Sab Sep 30, 2017 6:23 pm

Re: Bucle en módulo

Mensajepor pitxiku » Vie Jun 24, 2022 2:34 pm

Yo tampoco, porque no sé cómo es tu código. En la página de ayuda de la instrucción, aparece un ejemplo donde usan DoEvents dentro de un bucle. En caso de que no haya bucles, se puede colocar cada x líneas. También puede ser que tengas una SQL a la que le cueste mucho ejecutarse. En este caso tendrás que ver si se puede ejecutar por partes o por grupos de registros.

Pero lo dicho, si no sabemos cómo es tu código, difícilmente podemos dar una ayuda más precisa.

Dayban
Nivel 5
Mensajes: 159
Registrado: Mié Sep 20, 2017 7:08 am

Re: Bucle en módulo

Mensajepor Dayban » Lun Jun 27, 2022 8:12 am

Buenos días,

El código es este:

Código: Seleccionar todo

Public Sub Patro2AUTO()
    Dim strsql As String
    Dim rstsql As DAO.Recordset
    Dim strCompara As String
    Dim rstCompara As DAO.Recordset
    Dim intEst As Integer
   
    Dim strPatro As String
    Dim rstPatro As DAO.Recordset
   
    Dim datIni As Date
    Dim datFin As Date
    Dim varRes As Variant
    Dim intRegs As Integer
    Dim intNMxCicles As Integer
    Dim i As Long
    Dim m As Long
   
    datIni = Now
   
    strsql = "SELECT Count(TC1C11.Id) AS CuentaDeId FROM TC1C11"
    Set rstsql = CurrentDb.OpenRecordset(strsql, dbOpenForwardOnly)
    intRegs = rstsql.Fields(0).Value
    rstsql.Close
    Set rstsql = Nothing
    intNMxCicles = intRegs / 3
   
   
   
    strsql = "SELECT TOpc.Id, TOpc.InfImpor FROM TOpc WHERE (((TOpc.Id)=2))"
    Set rstsql = CurrentDb.OpenRecordset(strsql, dbOpenSnapshot)
    If rstsql.EOF = rstsql.BOF And rstsql.EOF = True Then
        MsgBox "Valor no encontrado", vbInformation
        rstsql.Close
        Set rstsql = Nothing
        Exit Sub
    End If
    intEst = rstsql.Fields(1).Value
    rstsql.Close
    Set rstsql = Nothing

   
   
   
    For i = 1 To intNMxCicles
       
        strsql = "SELECT TResul.Id, TResul.C1 FROM TResul WHERE (((TResul.Id)>=" & intEst & "))"
        Set rstsql = CurrentDb.OpenRecordset(strsql, dbOpenForwardOnly)
        For m = 1 To i
            rstsql.MoveNext
        Next m
       
        Do Until rstsql.EOF
            strCompara = "SELECT TC1C11.Id, TC1C11.N1 FROM TC1C11 WHERE (((TC1C11.Id)=" & (rstsql!ID - i) & "))"
            Set rstCompara = CurrentDb.OpenRecordset(strCompara, dbOpenForwardOnly)
            If rstsql!ID <> (rstCompara!ID + i) Then
                MsgBox "No pot ser que els id siguin diferents", vbCritical, "Error"
                Exit Sub
            End If
            strPatro = "SELECT TPatrons2AUTO.NumC1, TPatrons2AUTO.NumC2, TPatrons2AUTO.nveg, TPatrons2AUTO.ntot,TPatrons2AUTO.nsalts"
            strPatro = strPatro & " FROM TPatrons2AUTO WHERE (((TPatrons2AUTO.NumC1)=" & rstsql!c1 & ") AND ((TPatrons2AUTO.NumC2)=" & rstCompara!N1 & ")"
            strPatro = strPatro & " AND ((TPatrons2AUTO.nsalts)=" & i & "))"
            Set rstPatro = CurrentDb.OpenRecordset(strPatro, dbOpenDynaset)
            If (rstPatro.EOF = rstPatro.BOF) And (rstPatro.EOF = True) Then
                With rstPatro
                    .AddNew
                    .Fields(0) = rstsql!c1.Value
                    .Fields(1) = rstCompara!N1.Value
                    .Fields(2) = 1
                    .Fields(3) = 1
                    .Fields(4) = i
                    .Update
                End With
                rstPatro.Close
                Set rstPatro = Nothing
                rstCompara.Close
                Set rstCompara = Nothing
                GoTo c1
            End If
            With rstPatro
                .Edit
                .Fields(2) = .Fields(2) + 1
                .Fields(3) = .Fields(2) + 1
                .Update
            End With
            rstPatro.Close
            Set rstPatro = Nothing
           
            strPatro = "SELECT TPatrons2AUTO.NumC1, TPatrons2AUTO.NumC2, TPatrons2AUTO.nveg, TPatrons2AUTO.ntot"
            strPatro = strPatro & " FROM TPatrons2AUTO WHERE (((TPatrons2AUTO.NumC1)=" & rstsql!c1 & ") AND ((TPatrons2AUTO.NumC2)<>" & rstCompara!N1 & ")"
            strPatro = strPatro & " AND ((TPatrons2AUTO.nsalts)=" & i & "))"
            Set rstPatro = CurrentDb.OpenRecordset(strPatro, dbOpenDynaset)
            If (rstPatro.EOF = rstPatro.BOF) And (rstPatro.EOF = True) Then
                rstPatro.Close
                Set rstPatro = Nothing
                rstCompara.Close
                Set rstCompara = Nothing
                GoTo c1
            End If
            Do Until rstPatro.EOF
                With rstPatro
                    .Edit
                    .Fields(3) = .Fields(2) + 1
                    .Update
                End With
                rstPatro.MoveNext
            Loop
            rstPatro.Close
            Set rstPatro = Nothing
            rstCompara.Close
            Set rstCompara = Nothing
c1:
            rstsql.MoveNext
        Loop
        rstsql.Close
        Set rstsql = Nothing
    Next i
   
    strPatro = "UPDATE TPatrons2AUTO SET TPatrons2AUTO.Total = [TPatrons2AUTO]![nveg]/[TPatrons2AUTO]![ntot]"
    CurrentDb.Execute strPatro
   
    datFin = Now
    varRes = DateDiff("s", datIni, datFin)
    MsgBox "Proceso finalizado correctamente" & vbCrLf & "Ha tardado: " & varRes & " segundos", vbInformation, "Resultado"
End Sub



Quitando el bucle del "For" todo va genial, y tarda nada y menos. Sé que al haber puesto el for, la cantidad de cálculos y demás que hace ha aumentado de forma exponencial, pero cómo al arrancar en muy poco rato access se queda en "no responde", no sé hasta qué punto sigue cálculando o en qué momento de verdad se ha bloqueado.
Mirando el administrador de tareas sí que da la sensación de funcionar, o sí al final cierras access a lo "burro" al reabrirlo se ve que estaba haciendo sus cálculos.
Había pensado en poner una barra de progreso, pero sinceramente, no creo que sirva de nada si access se queda en ese estado...
No sé si tu sugerencia del "DoEvents" servirá en estos casos, porque por mucho que me miro la ayuda no entiendo ni cómo funciona ni en qué momentos se ha de usar... :(
Cómo siempre... gracias por vuestro tiempo y ayuda!
Saludos

pitxiku
VIP
Reto02
Mensajes: 585
Registrado: Sab Sep 30, 2017 6:23 pm

Re: Bucle en módulo

Mensajepor pitxiku » Lun Jun 27, 2022 1:28 pm

DoEvents no va a conseguir que el código se ejecute más rápido; de hecho, al devolver parcialmente el control a Windows para que se ejecuten otras aplicaciones y se actualicen las ventanas, va a ser más lento. Pero si el código está bien y Access no entra en bucle infinito, verás que Access no se congela. Puedes empezar con algo así:

Código: Seleccionar todo

    For i = 1 To intNMxCicles
       DoEvents


Y ver si realmente acaba el bucle. Después puedes ir ajustando, de forma que el DoEvents se ejecute 1 de cada 10 veces, por ejemplo.

Y si quieres barras de progreso, puedes usar la de Access. Pero en este caso, es más que recomendable usar DoEvents para que se actualicen las pantallas:

- https://docs.microsoft.com/es-es/office ... ress-meter

Dayban
Nivel 5
Mensajes: 159
Registrado: Mié Sep 20, 2017 7:08 am

Re: Bucle en módulo

Mensajepor Dayban » Lun Jun 27, 2022 7:59 pm

Con tu ejemplo, si no he entendido mal, el doevents se ejecutará en cada bucle del For?

pitxiku
VIP
Reto02
Mensajes: 585
Registrado: Sab Sep 30, 2017 6:23 pm

Re: Bucle en módulo

Mensajepor pitxiku » Mar Jun 28, 2022 9:00 am

En el ejemplo que he puesto, sí. Tu puedes ajustar para que se ejecute cada x veces, por ejemplo. Eso depende de lo que ralentize al código el DoEvents y de cuan importante es que no parezca que se cuelga Access.

Dayban
Nivel 5
Mensajes: 159
Registrado: Mié Sep 20, 2017 7:08 am

Re: Bucle en módulo

Mensajepor Dayban » Mar Jun 28, 2022 9:08 am

Lo acabo de probar y genial, ese estado de bloqueo ha desaparecido y junto a la barra de progreso queda claro que funciona.
Muchísimas gracias!!


Volver a “Código VBA”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 13 invitados