Consultar datos distintos en una misma tabla de datos
Augusto, soy Ricardo de nuevo, ayer te hice esta misma pregunta, pero parece que no te llego porque no me sale como pregunta activa, de lo que te pregunte anteriormente sobre como recorrer una base de datos esta todo bien pero hay algo que necesito saber, y es si con Recordset dentro de un ciclo, podría comparar dos datos de una misma tabla, ya sea cual es el mayor por ejemplo, pero siendo estos dos datos no consecutivos (comparar por ejemplo el primero de la tabla con el 320 de la misma y después el segundo con el 321 y así sucesivamente) y si no es posible con recordset, como podría hacerlo.
Y una segunda consulta que seria que trabajo con una base de datos que ya tiene muchas consultas y tablas que se crean a partir de ellas, y lo que necesito hacer es utilizar una tabla de las que ya te mencioné, que contiene una lista de lecturas por hora en un mes (24x30) y que corresponden a muchos equipos (400) y están todos juntos, y la idea es calcular el promedio diario y el máximo diario (serian dos tablas) para cada equipo y guardarlo en otra tabla (30 datos por cada equipo). Para ello primero ordené dichos datos, pero cuando quieria registrar por día los máximos y el promedio, las opciones de access no lo permiten (me las calcula para el total de la tabla y no una parte de ella que es lo que necesito) y no se si a través de código es posible.
Y una segunda consulta que seria que trabajo con una base de datos que ya tiene muchas consultas y tablas que se crean a partir de ellas, y lo que necesito hacer es utilizar una tabla de las que ya te mencioné, que contiene una lista de lecturas por hora en un mes (24x30) y que corresponden a muchos equipos (400) y están todos juntos, y la idea es calcular el promedio diario y el máximo diario (serian dos tablas) para cada equipo y guardarlo en otra tabla (30 datos por cada equipo). Para ello primero ordené dichos datos, pero cuando quieria registrar por día los máximos y el promedio, las opciones de access no lo permiten (me las calcula para el total de la tabla y no una parte de ella que es lo que necesito) y no se si a través de código es posible.
1 Respuesta
Respuesta de Augusto Cesar
1
1
Augusto Cesar, El tiempo es el recurso mas valioso que tenemos
La respuesta está en el mail anterior, no es necesario un bucle si buscas con indice y ademas así es más rápido
comparo dos datos
--------------------------------------------------------------------------
La cabecera como anteriormente y supongamos que ya tenemos la tabla abierta y el recordset se llama pagos
depende lo que vayas a comparar deberíamos utilizar una variable para guardar el valor antes de moverme al otro registro ( con el que voy a comparar), suponiendo que comparo datos numéricos.:
--------------------------------------------------------------------------------------------------
Dim aux as integer ' defino una varible de tipo entero
pagos.index ="xxxxxx" ' nombre del indice con que vas a buscar
pagos.seek "=", 100 ' busco el registro cuyo indice es 100
aux = pagos![total] ' asigno a la variable el valor del campo "total" para el registro 100
pagos.seek "=", 28 ' me muevo al registro 28 y ahora comparo
if aux > pagos![total] then ' si lo que esta en la variable es mayor que total (del 28)
Pagos. Edit ' voy a escribir en la tabla o lo que sea
...
pagos.update
pagos.close
End if
Para no tener que repetir el procedimiento por cada valor se supone que ya tienes los dos vales de los indices que vas a comparar podría ser así
Public sub compara ( n1 , n2 as integer )
cuando llegues a pagos.seek pones
pagos.seek "=" , n1 ' o tambien n2 porque pasamos estos valores al procedimiento
............
End sub
Ponemos public en vez de private para que puedas llamar a la función desde cualquier lugar de la aplicación
la llamada seria más o menos así
Call compara ( 100, 28) ' llamamos a la funcion desde cualquier lugar del codigo
call compara ( 200, 35) etc
Contestando a lo segundo lo que no se puede hacer por código no se puede hacer de ninguna manera
asique un bucle while que cuente los registros que deben cumplir una condición
-----------------------------------------------------------------------------------------------
public function promedio ( valor as integer ) as integer
while not pagos.EOF
if pagos![total] = valor then ' por ejem
C= C+1 ' cuentos los registros que tienen el valor pasado como parametro
aux = aux+pagos![importe] ' acumulo el importe de cada registro = valor
end if
pagos.movenext
¿Wend ' ya tengo el total en la variable C previamente definida no?
Promedio = Aux/ C ' saco el promedio de los registros contados
End function
Llamo a la función pero como devuelve un valor necesariamente lo tengo que poner en un control o una variable
ej en otro procedimiento
dim totalp as integer
totalp = promedio ( 20 ) ' me cuenta los registros que tienen el valor 20 y saca su promedio del campo que yo indique en el primer procedimiento claro
Bueno espero saques algo de esto saludos
comparo dos datos
--------------------------------------------------------------------------
La cabecera como anteriormente y supongamos que ya tenemos la tabla abierta y el recordset se llama pagos
depende lo que vayas a comparar deberíamos utilizar una variable para guardar el valor antes de moverme al otro registro ( con el que voy a comparar), suponiendo que comparo datos numéricos.:
--------------------------------------------------------------------------------------------------
Dim aux as integer ' defino una varible de tipo entero
pagos.index ="xxxxxx" ' nombre del indice con que vas a buscar
pagos.seek "=", 100 ' busco el registro cuyo indice es 100
aux = pagos![total] ' asigno a la variable el valor del campo "total" para el registro 100
pagos.seek "=", 28 ' me muevo al registro 28 y ahora comparo
if aux > pagos![total] then ' si lo que esta en la variable es mayor que total (del 28)
Pagos. Edit ' voy a escribir en la tabla o lo que sea
...
pagos.update
pagos.close
End if
Para no tener que repetir el procedimiento por cada valor se supone que ya tienes los dos vales de los indices que vas a comparar podría ser así
Public sub compara ( n1 , n2 as integer )
cuando llegues a pagos.seek pones
pagos.seek "=" , n1 ' o tambien n2 porque pasamos estos valores al procedimiento
............
End sub
Ponemos public en vez de private para que puedas llamar a la función desde cualquier lugar de la aplicación
la llamada seria más o menos así
Call compara ( 100, 28) ' llamamos a la funcion desde cualquier lugar del codigo
call compara ( 200, 35) etc
Contestando a lo segundo lo que no se puede hacer por código no se puede hacer de ninguna manera
asique un bucle while que cuente los registros que deben cumplir una condición
-----------------------------------------------------------------------------------------------
public function promedio ( valor as integer ) as integer
while not pagos.EOF
if pagos![total] = valor then ' por ejem
C= C+1 ' cuentos los registros que tienen el valor pasado como parametro
aux = aux+pagos![importe] ' acumulo el importe de cada registro = valor
end if
pagos.movenext
¿Wend ' ya tengo el total en la variable C previamente definida no?
Promedio = Aux/ C ' saco el promedio de los registros contados
End function
Llamo a la función pero como devuelve un valor necesariamente lo tengo que poner en un control o una variable
ej en otro procedimiento
dim totalp as integer
totalp = promedio ( 20 ) ' me cuenta los registros que tienen el valor 20 y saca su promedio del campo que yo indique en el primer procedimiento claro
Bueno espero saques algo de esto saludos
Augusto, primero que todo perdona por no responderte antes, pero tenia problemas para conectarme a internet, gracias por tu ayuda, el programa casi funciona de maravillas, lo único que me falta por hacer y que te quiero preguntar es como hago para que una consulta, que crea una tabla con nombres de campo de otras tablas, cree una nueva columna dentro de la tabla que siempre crea, pero con un nombre de campo que no exista en ninguna tabla (que sea totalmente nuevo, si es que me entiendes lo que quiero decir) y que tenga como valor por defecto el numero cero, porque cuando lo hago en la tabla de manera tradicional, se pierde el campo cada vez que ejecuto la consulta. Esperando que me hayas podido entender, me despido y nuevamente gracias totales.
Saludos, Ricardo.
Saludos, Ricardo.
Augusto, ahora que iba a probar el programa con la base de datos, no se que pasa, pareciera que queda en un loop, te anexo el código por si ves lo que yo no:
Option Compare Database
'Solo devuelve el minimo para dar la mayor fraccion en una comparacion mas adelante
Function minimo(x As Double, y As Double) As Integer
If (x < y) Then
minimo = 1
Else
minimo = 0
End Function
Public Sub ProgramaAlim()
Dim db As Database
Dim registro111 As Recordset
Dim registro222 As Recordset
Dim num As Double, auxIc As Double, calc As Double, frac As Double
Dim i As Integer, j As Integer, min As Integer, counter As Long
Dim word As String, auxNa As String
Set db = CurrentDb
'abro dos tablas de la base de datos, que son creadas por dos consultas
Set registro111 = db.OpenRecordset("0025 I_Alim_max_diario")
Set registro222 = db.OpenRecordset("003 I_max_prom_desv")
registro222.Edit
registro111.Edit
'variable word para comparar que ambos nombres sean idénticos
word = registro222![Nombre Alimentador]
While Not registro111.EOF
If (word = registro111![Nombre Alimentador]) Then
If (registro111![MáxDeIc] > (registro222![Promedio Ic] + (registro222![Desv Ic]) * (registro111![Crit_DESV]))) Then
' registro en una tabla valor 1 para diferenciar de los demas
registro111![Not Reprs] = 1
registro111.MoveNext
End If
Else
registro222.MoveNext
word = registro222![Nombre Alimentador]
End If
Wend
'actualizo ambas tablas
registro111.Update
registro222.Update
'me posiciono nuevamente en la primera posicion del registro
registro111.MoveFirst
j = 7
i = 1
'reviso los datos con un nuevo criterio
Do While Not registro111.EOF
auxNa = registro111![Nombre Alimentador]
auxIc = registro111![MáxDeIc]
registro111.Index = "FECHA"
j = j + i
registro111.Seek "=", j
If (registro111![MáxDeIc] = Null) Then
Exit Do
End If
If (auxNa = registro111![Nombre Alimentador]) Then
calc = registro111![MáxDeIc] - auxIc
min = minimo(registro111![MáxDeIc], auxIc)
If (min = 1) Then
frac = cal / registro111![MáxDeIc]
Else
frac = cal / auxIc
End If
If (frac > 0.6 Or frac < (-0.6)) Then
registro111![Not Reprs] = 1
End If
registro111.Index = "FECHA"
registro111.Seek "=", i
registro111.MoveNext
i = i + 1
Else
i = j
registro111.Index = "FECHA"
registro111.Seek "=", i
j = 7
End If
Loop
'cierro las tablas
registro111.Close
registro222.Close
End Sub
Después llamo a este sub a través de un botón que ademas tiene una etiqueta, con el siguiente código:
Private Sub Comando12_Click()
DoCmd.SetWarnings False
DoCmd.Hourglass True
msg = "Proceso en curso..."
msg1 = "PROCESO TERMINADO"
Forms![Principal]![Texto14] = msg
Call ProgramaAlim
DoCmd.Hourglass False
Forms![Principal]![Texto14] = msg1
DoCmd.SetWarnings True
End Sub
Esperando no ser de mucha molestia, se despide:
Ricardo.
Option Compare Database
'Solo devuelve el minimo para dar la mayor fraccion en una comparacion mas adelante
Function minimo(x As Double, y As Double) As Integer
If (x < y) Then
minimo = 1
Else
minimo = 0
End Function
Public Sub ProgramaAlim()
Dim db As Database
Dim registro111 As Recordset
Dim registro222 As Recordset
Dim num As Double, auxIc As Double, calc As Double, frac As Double
Dim i As Integer, j As Integer, min As Integer, counter As Long
Dim word As String, auxNa As String
Set db = CurrentDb
'abro dos tablas de la base de datos, que son creadas por dos consultas
Set registro111 = db.OpenRecordset("0025 I_Alim_max_diario")
Set registro222 = db.OpenRecordset("003 I_max_prom_desv")
registro222.Edit
registro111.Edit
'variable word para comparar que ambos nombres sean idénticos
word = registro222![Nombre Alimentador]
While Not registro111.EOF
If (word = registro111![Nombre Alimentador]) Then
If (registro111![MáxDeIc] > (registro222![Promedio Ic] + (registro222![Desv Ic]) * (registro111![Crit_DESV]))) Then
' registro en una tabla valor 1 para diferenciar de los demas
registro111![Not Reprs] = 1
registro111.MoveNext
End If
Else
registro222.MoveNext
word = registro222![Nombre Alimentador]
End If
Wend
'actualizo ambas tablas
registro111.Update
registro222.Update
'me posiciono nuevamente en la primera posicion del registro
registro111.MoveFirst
j = 7
i = 1
'reviso los datos con un nuevo criterio
Do While Not registro111.EOF
auxNa = registro111![Nombre Alimentador]
auxIc = registro111![MáxDeIc]
registro111.Index = "FECHA"
j = j + i
registro111.Seek "=", j
If (registro111![MáxDeIc] = Null) Then
Exit Do
End If
If (auxNa = registro111![Nombre Alimentador]) Then
calc = registro111![MáxDeIc] - auxIc
min = minimo(registro111![MáxDeIc], auxIc)
If (min = 1) Then
frac = cal / registro111![MáxDeIc]
Else
frac = cal / auxIc
End If
If (frac > 0.6 Or frac < (-0.6)) Then
registro111![Not Reprs] = 1
End If
registro111.Index = "FECHA"
registro111.Seek "=", i
registro111.MoveNext
i = i + 1
Else
i = j
registro111.Index = "FECHA"
registro111.Seek "=", i
j = 7
End If
Loop
'cierro las tablas
registro111.Close
registro222.Close
End Sub
Después llamo a este sub a través de un botón que ademas tiene una etiqueta, con el siguiente código:
Private Sub Comando12_Click()
DoCmd.SetWarnings False
DoCmd.Hourglass True
msg = "Proceso en curso..."
msg1 = "PROCESO TERMINADO"
Forms![Principal]![Texto14] = msg
Call ProgramaAlim
DoCmd.Hourglass False
Forms![Principal]![Texto14] = msg1
DoCmd.SetWarnings True
End Sub
Esperando no ser de mucha molestia, se despide:
Ricardo.
Parece que has usado bien algunos temas de los que hablamos, queda el reloj de arena y no te deja salir, pues eso si es un loop, se queda sin ram y ejecutando el mismo, para detectar errores de ese tipo te aconsejo que que llames a cada procedimiento en forma individual, ya que hay una opción que permite detectar errores pero los loops no los ataja . ya me has intrigado, ¿para qué es todo esto?, si quieres me cuentas
If (word = registro111![Nombre Alimentador]) Then
If (registro111![MáxDeIc] > (registro222![Promedio Ic] + (registro222![Desv Ic]) * (registro111![Crit_DESV]))) Then
' registro en una tabla valor 1 para diferenciar de los demas
registro111![Not Reprs] = 1
registro111.MoveNext
End If
Else
registro222.MoveNext --> ESTA LINEA DE CODIGO VA ANTES DEL WEND
( Y NO DENTRO DEL IF PORQUE SINO EL BUCLE NO AVANZA NUNCA CUANDO NO ENTRE AL IF Y NO SALE DEL WHILE )
word = registro222![Nombre Alimentador]
End IF
If (word = registro111![Nombre Alimentador]) Then
If (registro111![MáxDeIc] > (registro222![Promedio Ic] + (registro222![Desv Ic]) * (registro111![Crit_DESV]))) Then
' registro en una tabla valor 1 para diferenciar de los demas
registro111![Not Reprs] = 1
registro111.MoveNext
End If
Else
registro222.MoveNext --> ESTA LINEA DE CODIGO VA ANTES DEL WEND
( Y NO DENTRO DEL IF PORQUE SINO EL BUCLE NO AVANZA NUNCA CUANDO NO ENTRE AL IF Y NO SALE DEL WHILE )
word = registro222![Nombre Alimentador]
End IF
Me olvidaba fíjate que en un recordset tiene que esta algún comando para crear un campo nuevo, no recuerdo pero debe existir entonces en ese mismo momento que lo creas le asignas después de edit el valor 0
Prueba con este comando donde rs es un recordset abierto
Rs. Append "nomcampo1", adinteger
Rs. Append "nomcampo2", advarchar, 30
Prueba con este comando donde rs es un recordset abierto
Rs. Append "nomcampo1", adinteger
Rs. Append "nomcampo2", advarchar, 30
Te cuento lo que hago, pero primero tengo dos dudas, la primera es que agregar un indice a una tabla que es creada a partir de una consulta pero cada vez que ejecuto la consulta, se pierde el indice, ¿así qué como lo debo hacer para el indice se mantenga a pesar de las consultas?.
La segunda consulta es que corregí el primer ciclo del programa anterior, con tu ayuda y estoy tratando de corregir el segundo ciclo pero parece que el problema es con los registros, da la impresión de que no los reconoce, pero el ciclo anterior funciona bien, y la pregunta es si hay que hacer algo con el registro(recordset) porque ya lo abrí, le puse edit, luego le agregue un valor y finalmente lo actualice (update) y no lo cierro hasta el final del programa. A continuación te adjunto el programa y parte del código que quiero me ayudes a solucionar:
Function minimo(x As Double, y As Double) As Integer
If (x < y) Then
minimo = 1
Else
minimo = 0
End Function
Public Sub ProgramaAlim()
Dim db As Database
Dim registro111 As Recordset
Dim registro222 As Recordset
Dim num As Double, auxIc As Double, calc As Double, frac As Double
Dim i As Integer, j As Integer, min As Integer, counter As Long
Dim word As String, auxNa As String
Set db = CurrentDb
Set registro111 = db.OpenRecordset("0025 I_Alim_max_diario")
Set registro222 = db.OpenRecordset("003 I_max_prom_desv")
registro222.Edit
registro111.Edit
'ACA VA EL CICLO QUE FUNCIONA BIEN
'//////////////////////////////////////////////////
'Luego posiciono nuevamente en la primera posicion de la tabla "0025..."
registro111.MoveFirst
j = 7
i = 1
frac = 0
Do While Not registro111.EOF
'guardo datos de la linea que leo para luego, a traves del indice cambiarme de linea
auxNa = registro111![Nombre Alimentador]
auxIc = registro111![MáxDeIc]
registro111.Index = "FECHA"
j = j + i
registro111.Seek "=", j
'SI EXISTE VALOR REALIZA LA TAREA
If (registro111![MáxDeIc] <> Null) Then
'COMPARA DATOS DE LA LINEA AUXILIAR CON LA ACTUAL
If (auxNa = registro111![Nombre Alimentador]) Then
calc = registro111![MáxDeIc] - auxIc
'LLAMO A UNA FUNCION PARA ASERGURAR QUE DIVIDA POR EL MENOR
min = minimo(registro111![MáxDeIc], auxIc)
If (min = 1) Then
frac = cal / registro111![MáxDeIc]
Else
frac = cal / auxIc
End If
'PREGUNTO SI ESTÁ DENTRO DEL RANGO Y REGISTRA ESE VALOR 1
If (frac > 0.6 Or frac < (-0.6)) Then
registro111.Edit
registro111![Not Reprs] = 1
registro111.Update
registro111.MoveNext
Else
registro111.MoveNext
End If
'LUEGO VUELVO A POSICIONARME EN LA POSICION SIGUIENTE DE LA QUE COMENCE EL CICLO
i = i + 1
registro111.Index = "FECHA"
registro111.Seek "=", i
'Si comparacion if (2° anidado) es false
Else
i = j
registro111.Index = "FECHA"
registro111.Seek "=", i
j = 7
End If
'SI NO ES DISTINTO DE NULL SE SALE DEL CICLO
Else
Exit Do
End If
Loop
registro111.Close
registro222.Close
End Sub
Estoy haciendo una practica en electricidad y debo corregir unas lecturas erróneas con un programa en VBA, y gracias a tu ayuda, voy muy bien. Saludos.
La segunda consulta es que corregí el primer ciclo del programa anterior, con tu ayuda y estoy tratando de corregir el segundo ciclo pero parece que el problema es con los registros, da la impresión de que no los reconoce, pero el ciclo anterior funciona bien, y la pregunta es si hay que hacer algo con el registro(recordset) porque ya lo abrí, le puse edit, luego le agregue un valor y finalmente lo actualice (update) y no lo cierro hasta el final del programa. A continuación te adjunto el programa y parte del código que quiero me ayudes a solucionar:
Function minimo(x As Double, y As Double) As Integer
If (x < y) Then
minimo = 1
Else
minimo = 0
End Function
Public Sub ProgramaAlim()
Dim db As Database
Dim registro111 As Recordset
Dim registro222 As Recordset
Dim num As Double, auxIc As Double, calc As Double, frac As Double
Dim i As Integer, j As Integer, min As Integer, counter As Long
Dim word As String, auxNa As String
Set db = CurrentDb
Set registro111 = db.OpenRecordset("0025 I_Alim_max_diario")
Set registro222 = db.OpenRecordset("003 I_max_prom_desv")
registro222.Edit
registro111.Edit
'ACA VA EL CICLO QUE FUNCIONA BIEN
'//////////////////////////////////////////////////
'Luego posiciono nuevamente en la primera posicion de la tabla "0025..."
registro111.MoveFirst
j = 7
i = 1
frac = 0
Do While Not registro111.EOF
'guardo datos de la linea que leo para luego, a traves del indice cambiarme de linea
auxNa = registro111![Nombre Alimentador]
auxIc = registro111![MáxDeIc]
registro111.Index = "FECHA"
j = j + i
registro111.Seek "=", j
'SI EXISTE VALOR REALIZA LA TAREA
If (registro111![MáxDeIc] <> Null) Then
'COMPARA DATOS DE LA LINEA AUXILIAR CON LA ACTUAL
If (auxNa = registro111![Nombre Alimentador]) Then
calc = registro111![MáxDeIc] - auxIc
'LLAMO A UNA FUNCION PARA ASERGURAR QUE DIVIDA POR EL MENOR
min = minimo(registro111![MáxDeIc], auxIc)
If (min = 1) Then
frac = cal / registro111![MáxDeIc]
Else
frac = cal / auxIc
End If
'PREGUNTO SI ESTÁ DENTRO DEL RANGO Y REGISTRA ESE VALOR 1
If (frac > 0.6 Or frac < (-0.6)) Then
registro111.Edit
registro111![Not Reprs] = 1
registro111.Update
registro111.MoveNext
Else
registro111.MoveNext
End If
'LUEGO VUELVO A POSICIONARME EN LA POSICION SIGUIENTE DE LA QUE COMENCE EL CICLO
i = i + 1
registro111.Index = "FECHA"
registro111.Seek "=", i
'Si comparacion if (2° anidado) es false
Else
i = j
registro111.Index = "FECHA"
registro111.Seek "=", i
j = 7
End If
'SI NO ES DISTINTO DE NULL SE SALE DEL CICLO
Else
Exit Do
End If
Loop
registro111.Close
registro222.Close
End Sub
Estoy haciendo una practica en electricidad y debo corregir unas lecturas erróneas con un programa en VBA, y gracias a tu ayuda, voy muy bien. Saludos.
- Compartir respuesta
- Anónimo
ahora mismo