Problema con Cursor en Access

Buenos días y gracias por adelantado:
Tengo una tabla con 23000 registros que recorro con un cursor de un recordset tipo DAO buscando una condición de un campo. Si no se cumple paso al siguiente, así hasta que se cumple. Lo que sucede es que en un momento dado el puntero "salta", es decir por ejemplo, va por el 3605 y cuando tiene que comparar el 3606 ¡No lo compara! Porque salta por ejemplo al 6600. Lo he programado para ir hacia delante, hacia detrás y nada "salta" es extrañísimo. Creo que puede estar relacionado con el número máximo de records que puede recorrer pero no he encontrado ninguna documentación. Te adjunto un trozo de código:
MES:
rsModificar.MoveNext
If Left(rsModificar.Fields(1), 2) <> strMesFin Then
GoTo MES
End If
Día:
rsModificar.MoveNext
If Mid(rsModificar.Fields(1), 4, 2) <> strDiaFin Then
intPuntero = rsModificar.Fields(0)
GoTo DIA
End If
Muchas gracias de nuevo

1 respuesta

Respuesta
1
Primer punto: NUNCA USAR LA SENTENCIA GOTO. Sólo usarla para control de errores.
La sentencia GOTO lía la patata mucho y el código queda muy difícil de leer.
Mejor usa for, while o cualquiera de los controles de flujo.
El programa que haces sería así:
Do
    RstModificar. MoveNext
loop until (left(rsModificar.Fields(1),2) = strMesFin)   
rsModificar.MoveNext
do until (mid(rsModificar.Fields(1),4,2) = strDiaFin)
    intPuntero=rsModificar.Fields(0)
    rsModificar.MoveNext
loop
Segundo punto: Nunca uses el número de columna para la colección Fields. Mejor usa el nombre de columna. Puedes hacerlo así:
RsModificar! IdDato
rsModificar![Fecha de Alta]
RsModificar("Fecha de Alta")
RsModificar. Fields("Fecha de Alta")
Todas son válidas y el código queda mucho más claro. Además puede haber reordenación de columnas y el código sigue funcionando.
TercerPunto: Usa el tipo de campos fecha para las fechas. Tienes muchas más herramientas para ello.
Por último. ¿Qué es lo que quieres hacer realmente? No de digas comparo con un valor, o cosas así. Dime algo como, encontrar las tres facturas de mayor valor en el último año y añadirles un 10 %. Seguramente es más fácil hacerlo en SQL que en VBA.
Gracias Jose por tu pronta respuesta:
Lo que hacemos en esta base de datos es simple pero tiene sus "rarezas".
Básicamente hemos creado una base de datos para poder recoger, imprimir y analizar unas tablas llenas de temperaturas que genera un autómata. Todo este proceso es fácil y funciona sin problemas. Lo que necesitamos generar con este código VBA es un formulario donde el cliente selecciona un intervalo inicial y final determinado por su fecha y hora . Entre estos dos intervalos debemos modificar los valores de la tabla mediante una fórmula. Por eso necesitamos saber cuantos registros hay en ese intervalo. Para ello empezamos a recorrer el recordset desde el principio hasta encontrar el mes, después el día y luego la hora de la fecha inicial y guardamos esa posición, continuamos hasta la posición de mes, día y hora final y guardamos en otra variable, así sabemos cuales son los registros que están en el intervalo, el problema se crea cuando el cursor del recordset "salta" a registros no consecutivos de la tabla.
En cuanto a los formatos creo que no podría aplicar el formato a los campos fácilmente porque el campo donde se guarda la fecha es de texto y tiene esta forma:
 MM/dd hh:mm:ss
Muchas gracias
Primero, el orden de las tablas es arbitrario. Access puede reordenar las tablas cuando lo crea conveniente (para ahorrar espacio, por ejemplo). Si abres la tabla directamente sin seleccionar un orden te puedes encontrar con cualquier cosa.
De todas formas, lo más fácil, como ya te adelanté, es usar SQL.
Lo que yo haría sería crear un nuevo campo en la tabla tipo Fecha/hora y "traducir" lo que te comunica el autómata a ese formato. Así después es mucho más fácil de manejar.
Supongo que tienes la fecha en un campo de 6 letras tipo formato americano mmddyy. Dime el formato de esa cadena de texto y te creo la consulta que te actualizará toda la tabla.
Después me pasas la fórmula que ejecutas y te pasaré la otra consulta para que te la ejecute.
La tabla tiene estos campos:
Id
Fecha-o
 Tª Cª Nº7
Corregido
Que a modo de ejemplo tienen estos datos en cada campo
1
02/27 12:24:18
11,1
N
En cuanto a la fórmula para modificar los registros la tengo programada así:
intValorInicioPendiente = rsModificar.Fields(2).Value
intAlfay = (rsModificar.Fields(2).Value - [Temperatura])
intAlfa = Atn(intAlfay / intContador)
For i = 1 To intContador
intResta = i * Tan(intAlfa)
rsModificar.Edit
rsModificar.Fields(2) = Round(intValorInicioPendiente - intResta, 1)
rsModificar.Fields(3) = "S"
rsModificar.Update
rsModificar.MoveNext
intPuntero = intPuntero + 1
Next i
Gracias de nuevo
Anda, pásame la función completa y no sólo un trozo, que me pierdo. ¿Cómo abres rsModificar? ¿Qué es Temperatura? ¿Por qué actualizas intPuntero?
Por otro lado, añade a la tabla un campo tipo fecha/hora llamado FECHA_CORRECTA
Después crea una consulta y pasa a SQL
UPDATE Nombre_Tabla
SET FECHA_CORRECTA=DateSerial(year(now),
val(left([FECHA-O],2),
val(mid([FECHA-O],4,2)) +
TimeSerial(val(mid([FECHA-O],7,2)),
val(mid([FECHA-O],10,2)),
val(mid([FECHA-O],13,2))
Y lo ejecutas.
Eso rellenará el campo FECHA_CORRECTA con la función de date serial + timeserial correspondiente. Vigila los valores de mid() que los haya puesto bien.
Hola de nuevo y de nuevo gracias por tu interés:
Te adjunto la sub completa. Para que puedas centrarme en el problema existen 3 partes diferenciadas en la misma:
Parte 1: controla los valores que mete el usuario en el formulario: esto funciona bien independientemente de que seguro que hay 20 formas de hacerlo mejor
Parte2: busca el intervalo de registros a modificar
Parte 3: Modifica los registros: esto funciona bien cuando los cursores de inicio y final son correctos. Sino se vuelve loco
Cuando me has comentado que las tablas no se guardan en orden he visto el origen del problema. Seguramente con un rsModificar=db1.OpenrecordSet(SELECT... ORDER BY...) funcionaria, pero aquí me pierdo un poco porque de SQL ando más escaso (también de VBA pero a base de pegarme y con vuestra ayuda creo que saldré con el problema)
Private Sub CORREGIR_Click()
Dim strMesInicio As String
Dim strMesFin As String
Dim strDiaInicio As String
Dim strDiaFin As String
Dim strHoraInicio As String
Dim strHoraFin As String
Dim strHoraminima As String
Dim dteHoraInicio As Date
Dim dteHoraFin As Date
Dim rsModificar As DAO.Recordset
Dim rsCopiar As DAO.Recordset
Dim db1 As Database
Dim intPuntero As Integer
Dim intPunteroInicio As Integer
Dim intPunteroFinal As Integer
Dim intPuntero1 As Integer
Dim intContador As Integer
Dim intAlfa As Double
Dim intAlfay As Double
Dim intValorInicioPendiente As Integer
Dim intValorFinalPendiente As Integer
Dim i As Integer
Dim intResta As Integer
Dim intAnswer1 As Integer
Dim dteHoraRecord As Date
Dim strHoraMinimaInicio As String
Dim strHoraMinimaFin As String
Dim i3 As Integer
On Error GoTo Error
'Variable para limite de modificiacion por dia'
strHoraminima = "00:30:00"
'determina valor de intContador en base al valor introducido [Temperatura] _
este contador servirá parala modificacion de valores'
If [Temperatura] > -20 Then
intContador = 6
Else
If [Temperatura] < -40 Then
intContador = 16
Else
intContador = 10
End If
End If
'Parte 1'
If CALENDAR1 = "" Then
MsgBox ("DEBE INTRUCIR FECHA INICIO")
Me.CALENDAR1.SetFocus
Exit Sub
Else
If CALENDAR2 = "" Then
MsgBox ("DEBE INTRODUCIR FECHA FIN")
Me.CALENDAR2.SetFocus
Exit Sub
Else
If CALENDAR2 < CALENDAR1 Then
MsgBox ("LA FECHA FIN DEBE SER MAYOR O IGUAL A LA FECHA INICIO")
Exit Sub
Else
If IsNull([Hora Inicio]) Then
MsgBox ("DEBE INTRODUCIR LA HORA DE INICIO")
Me.Hora_Inicio.SetFocus
Exit Sub
Else
If [Temperatura] = Null Then
MsgBox ("DEBE INTRODUCIR LA TEMPERATURA OBJETIVO")
Me.Hora_Fin.SetFocus
Exit Sub
Else
If IsNull([Hora Fin]) Then
MsgBox ("DEBE INTRODUCIR LA HORA DE FIN")
Me.Hora_Fin.SetFocus
Exit Sub
Else
If Left([FECHA-O], 2) > Mid([CALENDAR1], 4, 2) Then
intAnswer1 = MsgBox("LA FECHA y HORA DE INICIO SELCCIONADA YA SE CORRIGIÓ ANTERIORMENTE" & vbCrLf & vbCrLf _
& "NO SE PERMITE HACERLO AUTOMÁTICAMENTE" & vbCrLf _
& "PUEDE HACERLO MEDIANTE LA PANTALLA INFERIOR", vbOK + vbCritical, " !!!!!! ADVERTENCIA IMPORTANTE")
Exit Sub
Else
If Left([FECHA-O], 2) = Mid([CALENDAR1], 4, 2) Then
If Mid([FECHA-O], 4, 2) > Left([CALENDAR1], 2) Then
intAnswer1 = MsgBox("LA FECHA y HORA DE INICIO SELCCIONADA YA SE CORRIGIÓ ANTERIORMENTE" & vbCrLf & vbCrLf _
& "NO SE PERMITE HACERLO AUTOMÁTICAMENTE" & vbCrLf _
& "PUEDE HACERLO MEDIANTE LA PANTALLA INFERIOR", vbOK + vbCritical, " !!!!!! ADVERTENCIA IMPORTANTE")
Exit Sub
Else
If Mid([FECHA-O], 4, 2) = Left([CALENDAR1], 2) Then
If dteHoraRecord > [Hora Inicio] Then
intAnswer1 = MsgBox("LA FECHA y HORA DE INICIO SELCCIONADA YA SE CORRIGIÓ ANTERIORMENTE" & vbCrLf & vbCrLf _
& "NO SE PERMITE HACERLO AUTOMÁTICAMENTE" & vbCrLf _
& "PUEDE HACERLO MEDIANTE LA PANTALLA INFERIOR", vbOK + vbCritical, " !!!!!! ADVERTENCIA IMPORTANTE")
Exit Sub
Else
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
'extraigo los valores de los datos aportados _
por el cliente para compararlos después
strMesInicio = Mid(CALENDAR1, 4, 2)
strMesFin = Mid(CALENDAR2, 4, 2)
strDiaInicio = Left(CALENDAR1, 2)
strDiaFin = Left(CALENDAR2, 2)
'si la hora tiene una sola cifra añadimos _
un cero delante
If Mid([Hora Inicio], 2, 1) = ":" Then
strHoraInicio = "0" & Left([Hora Inicio], 1)
strHoraMinimaInicio = strHoraInicio & Right([Hora Inicio], 6)
Else
strHoraInicio = Left([Hora Inicio], 2)
strHoraMinimaInicio = strHoraInicio & Right([Hora Inicio], 6)
End If
If strHoraMinimaInicio < strHoraminima Then
MsgBox ("LA HORA DE INICIO DEBE SER POSTERIOR A LAS 00:30")
Exit Sub
End If
If Mid([Hora Fin], 2, 1) = ":" Then
strHoraFin = "0" & Left([Hora Fin], 1)
strHoraMinimaFin = strHoraFin & Right([Hora Fin], 6)
Else
strHoraFin = Left([Hora Fin], 2)
strHoraMinimaFin = strHoraFin & Right([Hora Fin], 6)
End If
If strHoraMinimaFin < strHoraminima Then
MsgBox ("LA HORA DE FINALIZACIÓN DEBE SER POSTERIOR A LAS 00:30")
Exit Sub
End If
'Parte 2
Set db1 = CurrentDb
Set rsModificar = db1.OpenRecordset("CAMARA-7")
rsModificar.MoveFirst
intPuntero = rsModificar.RecordCount
rsModificar.MoveLast
rsModificar.MoveFirst
'busco mes de inicio
Do
rsModificar.MoveNext
Loop Until Left(rsModificar![FECHA-O], 2) = strMesInicio
'busco dia de inicio
Do
rsModificar.MoveNext
Loop Until Mid(rsModificar![FECHA-O], 4, 2) = strDiaInicio
'busco hora de inicio superior a la deseada
Do
rsModificar.MoveNext
strHoraInicio = Right(rsModificar![FECHA-O], 8)
dteHoraInicio = CDate(strHoraInicio)
Loop Until dteHoraInicio > [Hora Inicio]
'guardo el orden del record de inicio
intPunteroInicio = rsModificar![Id]
'busco mes de final
Do
rsModificar.MoveNext
Loop Until Left(rsModificar![FECHA-O], 2) = strMesFin
'busco dia final
Do
rsModificar.MoveNext
Loop Until Mid(rsModificar![FECHA-O], 4, 2) = strDiaFin
'busco hora de fin superior a la deseada
Do
rsModificar.MoveNext
strHoraFin = Right(rsModificar![FECHA-O], 8)
dteHoraFin = CDate(strHoraFin)
Loop Until dteHoraFin > [Hora Fin]
'guardo el orden del record final
intPunteroFinal = rsModificar![Id]
'compruebo que existen suficiente records para _
poder hacer la modifciacion automatica
If (intPunteroFinal - intPunteroInicio) < (intContador * 2) Then
MsgBox ("EL INTERVALO ENTRE LAS FECHAS SELECCIONADAS ES PEQUEÑO PARA PODER CORREGIR CORRECTAMENTE")
Exit Sub
End If
'Parte 3 _
A partir de aquí está la modificacicón _
de datos. Esto funciona correctamente cuando _
los punteros intPunteroFinal e intPunteroInicio _
son correctos y no "saltan"
i3 = 0
Inicio:
If rsModificar(3) = "N" Then
rsModificar.Edit
rsModificar![CORREGIDO] = "S"
rsModificar.Update
i3 = i3 + 1
rsModificar.MovePrevious
If rsModificar.BOF = True Then
GoTo Adelante
Else
intPuntero = intPuntero - 1
GoTo Inicio
End If
End If
Adelante:
For i = 1 To i3
rsModificar.MoveNext
intPuntero = intPuntero + 1
Next i
'calculo del primer intervalo con valores de la tangente _
hasta el valor de intcontador
intValorInicioPendiente = rsModificar![Tª Cª Nº7].Value
intAlfay = (rsModificar![Tª Cª Nº7].Value - [Temperatura])
intAlfa = Atn(intAlfay / intContador)
Exit Sub
For i = 1 To intContador
intResta = i * Tan(intAlfa)
rsModificar.Edit
rsModificar![Tª Cª Nº7] = Round(intValorInicioPendiente - intResta, 1)
rsModificar![CORREGIDO] = "S"
rsModificar.Update
rsModificar.MoveNext
intPuntero = intPuntero + 1
Next i
'relleno con el valor actual de temperatura y un aleatorio _
hasta cuando debe empezar a subir
For i = 1 To (intPunteroFinal - intContador - intPuntero)
rsModificar.Edit
rsModificar![Tª Cª Nº7] = Round(([Temperatura] - Rnd), 1)
rsModificar![CORREGIDO] = "S"
rsModificar.Update
rsModificar.MoveNext
intPuntero = intPuntero + 1
Next i
'calculo de la pendiente de bajada
For i = 1 To intContador
rsModificar.MoveNext
intPuntero = intPuntero + 1
Next i
intAlfay = (rsModificar![Tª Cª Nº7].Value - [Temperatura])
intAlfa = Atn(intAlfay / intContador)
For i = 1 To intContador
rsModificar.MovePrevious
intPuntero = intPuntero - 1
Next i
'relleno de calores de pendiente de bajada
For i = 1 To intContador
intResta = i * Tan(intAlfa)
rsModificar.Edit
rsModificar![Tª Cª Nº7] = Round(([Temperatura] + intResta), 1)
rsModificar![CORREGIDO] = "S"
rsModificar.Update
rsModificar.MoveNext
intPuntero1 = intPuntero1 + 1
Next i
Me!Texto24.SetFocus
DoCmd.FindRecord "N"
CALENDAR1.Value = (Mid(Me![FECHA-O].Value, 4, 2) & "/" & Left(Me![FECHA-O], 2) & "/08")
CALENDAR2.Value = (Mid(Me![FECHA-O].Value, 4, 2) & "/" & Left(Me![FECHA-O], 2) & "/08")
Exit Sub
Error:
intAnswer1 = MsgBox("LAS FECHA INICIAL O FINAL ESTÁ FUERA DEL RANGO REGISTRADO POR EL AUTÓMATA", vbOKOnly + vbCritical, "ERROR")
End Sub
Veo que me has hecho caso y el código está bastante más legible. El .value del objeto field es el campo predeterminado por lo que la mayoría de veces puedes obviarlo. Yo suelo escribir cosas como
rsModificar!Nombre = "Jose"
Si al poner nombres a los campos de las tablas evitas espacios y símbolos no hacen falta los corchetes.
Bueno, ahora a lo que vamos.
Dado que los datos de fecha al ordenarlos alfabéticamente te coinciden con el orden de fecha, ya que los has ordenado de mayor a menor importancia (es decir mes-día-hora-minuto-segundo) puedes usar ese orden para el mayor menor y olvidarte de la mitad del código
Con:
dim strSQL as string <- al principio
y despues:
strSQL = "SELECT * FROM [CAMARA-7] WHERE [FECHA-O] BETWEEN (""" & _
    CALENDAR1 & """,""" & CALENDAR2 & """) ORDER BY [FECHA-O]"
set rsModificar=db.openrecordset(strsql,dbopendynaset)
Ahora el recordset que te entregan está ordenado y sólo contiene los registros entre la fecha de inicio y la final.
;)

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas