Añadir criterio fecha más reciente a buscador en formulario

Tengo un buscador para datos genéticos en formulario de Access a partir de lo que se selecciona en diferentes cuadros combinados (gen, exon, etc.). Quiero añadir otro botón para que, al pulsarlo y también a partir de lo que se seleccione en los cuadros, me muestre únicamente un registro, el que tiene la fecha más reciente (en la tabla de datos hay un campo Fecha también relleno), y no sé como hacerlo la verdad.

El código que tengo es el siguiente:

'Declaramos las variables
Dim vGen As String
Dim vExon As String
Dim vCoding As String
Dim vLargo As Integer
Dim miFiltro As String
Dim miSQL As String

miSQL = "SELECT * FROM NGS "

'Cogemos los valores que hayamos seleccionado como filtro
vGen = Nz(Me.cboGen.Value, "")
vCoding = Nz(Me.cboCoding.Value, "")
vExon = Nz(Me.cboExon.Value, "")

'Inicializamos el filtro

miFiltro = ""

'Filtro por GEN

If vGen <> "" Then
miFiltro = miFiltro & "AND [Gen]='" & vGen & "'"
End If

'FILTRO POR CODING
If vCoding <> "" Then
miFiltro = miFiltro & "AND [Coding] = '" & vCoding & "'"
End If

'FILTRO POR EXON
If vExon <> "" Then
miFiltro = miFiltro & "AND [Exon] = '" & vExon & "'"
End If

'Cogemos la longitud del filtro

vLargo = Len(miFiltro)

'Recomponemos el filtro eliminando el primer 'AND'
If vLargo > 0 Then
miFiltro = Right(miFiltro, vLargo - 4)
End If

'Aplicamos el filtro al formulario
Me.Filter = miFiltro
Me.FilterOn = True

miSQL = miSQL & "WHERE " & miFiltro
Me.Lista0.RowSource = miSQL
Me. Lista0. Requery

Soy un novato total en Access así q disculpadme si hay alguna barbaridad en el código :)

2 Respuestas

Respuesta
1

Para recuperar únicamente un registro, puede especificar la cláusula "TOP" en la sentencia de consulta:

SELECT TOP 1 * FROM....

Para que el registro recuperado sea el de la fecha más reciente, deberá ordenar la selección por medio de "ORDER BY" según el campo de fecha, en orden descendente.

Es decir:

SELECT TOP 1 * FROM NGS WHERE (...) ORDER BY Fecha DESC

Gracias por la ayuda Poli.

La clausula "TOP" me funciona sin problemas, pero no consigo ordenar la selección con "ORDER BY" (la búsqueda me devuelve siempre 0 resultados).

He probado con:

miSQL = "SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC"

miSQL = "SELECT TOP 1 * FROM NGS ORDER BY NGS.Fecha DESC"

Y también con otros campos en lugar de Fecha pero no obtengo resultados. ¿Es necesario añadir la clausula WHERE o algún otro criterio?

La cláusula TOP lo único que hace es reducir el conjunto de registros devueltos. No filtra, ni ordena. Por tanto, si no pone condiciones en el WHERE y no ordena por ningún campo, debería obtener 1 registro como resultado, siempre que la tabla contenga datos.

Haga la prueba sin ordenar y sin poner ninguna condición el WHERE.

(Por cierto, si está usted especificando las condiciones en miSQL no veo la necesidad de usar Filter y FilterON. La sentencia SQL ya está filtrando los datos.)

Si logra obtener resultados con "SELECT TOP 1 * FROM NGS", puede añadir el orden, con "SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC". Debería seguir obteniendo algún resultado (el registro con mayor fecha). Y si esto le funciona, puede añadir las condiciones que estaba usted construyendo en miFiltro. Pero, insisto, si las está incluyendo en miSQL olvídese del tema Filter.

Con "SELECT TOP 1 * FROM NGS" obtengo un resultado, sí. 

Sin embargo, cuando añado la cláusula ORDER BY Fecha DESC me devuelve 0 resultados. No sé si afecta el hecho de que algunos registros no tienen fecha, pero he probado a intentar ordenar por otro campo que está relleno en todos los registros y tampoco funciona, me devuelve 0 resultados de nuevo.

He eliminado el Filter y FilterON, como comentaba, y todo funciona correctamente :)

Lo que me comenta es imposible.

Si cuando usa "SELECT TOP 1 * FROM NGS" obtiene resultados, es imposible que si usa "SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC" no los obtenga. Hay algo que nos estamos perdiendo. Como le indicaba antes, el efecto de ORDER BY es únicamente el de ordenar los resultados. Por tanto, no pueden "desaparecer" registros.

Olvídese por un momento del código. En Access, abra el diseñador de consultas, visualice la sentencia SQL y haga la prueba: pruebe tanto con "SELECT TOP 1 * FROM NGS" como con "SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC". Dígame lo que obtiene.

Al usar en el diseñador de consultas "SELECT TOP 1 * FROM NGS" me abre un único registro en la tabla. 

Al usar "SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC" me devuelve 6 registros, todos de fecha 02 de febrero (el dato más reciente de fecha en la tabla). 

SELECT TOP 1 siempre devolverá un único registro. No puede ser que por el hecho de añadirle el ORDER BY le devuelva 6, porque usted está indicando que le devuelva únicamente 1 registro (TOP 1)

No sé si tendrá usted manera de subir la base de datos a algún lugar para que me la pueda descargar y echarle un vistazo, porque aquí hay al algo que no cuadra.

Claro, voy a subirlo a algún repositorio y le mando el enlace en breve, muchísimas gracias por la ayuda

https://we.tl/t-Eo8vnKs8ym 

Avísame por favor si no le funciona, gracias de nuevo!

En efecto, ¡Tiene usted toda la razón!. La verdad es que hace ya algunos años que no uso Access y no había visto este comportamiento nunca. Pero resulta que está documentado. Puede verlo aquí:

sql - Why does this Select top 1 query return more than one result? - Stack Overflow

Para evitarlo, podría añadir el campo Id, que es único, al orden de la consulta. Algo así como:

SELECT TOP 1 NGS.*
FROM NGS
ORDER BY Fecha DESC, Id DESC;

Efectivamente añadiendo el campo Id la consulta ejecutada devuelve un único valor :)

Sin embargo, si añado el mismo código al formulario "Buscador":

SELECT TOP 1 * FROM NGS ORDER BY Fecha DESC, Id DESC

Como podrá comprobar, la búsqueda en el formulario no devuelve ningún resultado. Es (desde la ignorancia) como si la selección de algún filtro (gen, exón u otro) fuera incompatible con el criterio de ordenar, no sé si me explico.

Ojo con los filtros porque cuando no se pone ninguno (mifiltro=""), la sentencia es incorrecta (tiene un WHERE sin condiciones):

"SELECT * FROM NGS WHERE ORDER BY Fecha DESC, Id DESC"

Cuando mifiltro = "" no debería aparecer el WHERE.

Muéstreme cómo ha construido la sentencia, porque a mí sí me devuelve resultados:

No sé si lo estoy entiendo bien, discúlpeme si no es el caso.

Originalmente tengo en el código del formulario Buscador: 

miSQL = "SELECT * FROM NGS" (y funciona correctamente)

Si sustituyo eso por:

miSQL = "SELECT * FROM NGS ORDER BY Fecha DESC, Id DESC"

El buscador me devuelve 0 resultados sea cual sea lo que selecciono en los cuadros:

Al inicializar el filtro efectivamente aparece miFiltro = ""

Y finalmente tengo:

miSQL = miSQL & "WHERE " & miFiltro
Me.Lista0.RowSource = miSQL
Me.Lista0.Requery

Ese es el único WHERE que aparece en mi código, ¿debería cambiarlo?

Mi objetivo es seleccionar en el buscador algún campo (gen, exon, otro) y que aparezca al pulsar el botón Buscar únicamente el registro con la fecha más actual. 

Le devuelve 0 registros no porque no los haya, sino porque cuando no selecciona usted ningún valor en los desplegables, su sentencia acaba siendo sintácticamente incorrecta. Cuando no hay ningún criterio de búsqueda, su variable mifiltro es "". Por tanto, la variable misql queda:

miSQL = miSQL & "WHERE " & miFiltro

"SELECT TOP 1 FROM NGS WHERE"

Y esa sentencia es incorrecta. No puede estar el WHERE cuando no hay condiciones.

Aprovechando el código que usted está usando, podría adaptarlo de la siguiente manera (lo digo por no rehacerlo todo):

Respuesta
1

Veo que está confundido si hay más de un registro con una misma fecha no sirve TOP 1 porque se debe utilizar es una consulta de agrupación tomando el máximo de la fecha y tomando el último ID o campo clave. Algo como:

TABLA

DISEÑO CONSULTA

ConsulTa en SQL:

SELECT Last(tblPruebaFecha.id) AS Elultimo, Max(tblPruebaFecha.fecha_reg) AS Fecha, Last(tblPruebaFecha.nota) AS LaNota
FROM tblPruebaFecha;

RESULTADO DE LA CONSULTA

Observe que a pesar de tener 3 registros con fecha 3/02/2022 obtengo el último.

Hágalo por SQL no necesita FILTER, si quiere envíeme la base datos con información ficticia a [email protected], favor en el asunto anotar la consulta.

Veo que se están complicando, utilizo For Each para recorrer los controles, es una forma de trabajar con bastantes controles reduciendo el código.

Adicioné 2 botones Buscar EPF, un botón para eliminar todos los filtros y 2 controles para el rango de fechas (se puede omitir)

Código del botón buscar epf

Private Sub btnBuscar_Click()
 Dim sFiltro As String
 Dim ctrl As Control
 Dim strSQL  As String
'Le indico el Nº de Columnas de la lista a mostrar con los resultados
Me.Lista0.ColumnCount = 17
'Le indico el ancho de cada columna
Me.Lista0.ColumnWidths = "3 cm; 3 cm; 1,4 cm; 2,4 cm; 1,3 cm; 5 cm; 5 cm; 3,5 cm; 3 cm; 2 cm; 2 cm; 3,5 cm; 3,5 cm; 2,5 cm; 3; 0 cm; 0 cm"
'Le indico que quiero el título de las columnas
Me.Lista0.ColumnHeads = True
 For Each ctrl In Me.Controls
   If ctrl.ControlType = acComboBox Then
     If ctrl.Value <> "" And ctrl.Tag <> "fecha" Then
      'sFiltro = sFiltro & ctrl.Tag & " LIKE '*" & ctrl.Value & "*'" & " AND " ' Esto para buscar con LIKE
      sFiltro = sFiltro & ctrl.Tag & "='" & ctrl.Value & "'" & " AND "
     End If
   End If
 Next
 If sFiltro <> "" Then
  sFiltro = Left(sFiltro, Len(sFiltro) - 4)
 End If
 'Esto si utiliza Fecha, en caso contrario comente estas líneas
 '************************************************************************************
  If IsDate(Me.fdesde) And IsDate(Me.fhasta) Then
   If sFiltro <> "" Then
    sFiltro = sFiltro & " AND fecha between " & "#" & _
    Format(fdesde, "mm/dd/yyyy") & "#" & " and #" & Format(fhasta, "mm/dd/yyyy") & "#"
   Else
   sFiltro = "fecha between " & "#" & _
    Format(fdesde, "mm/dd/yyyy") & "#" & " and #" & Format(fhasta, "mm/dd/yyyy") & "#"
   End If
  End If
 '**********************************************************************************
strSQL = "SELECT * FROM NGS WHERE " & sFiltro
Me.Lista0.RowSource = strSQL
'Indicar número de registros encontrados
If Me.Lista0.ListCount = 0 Then
Me.Textoencontrado = "0"
Me.textoporcen = "0"
Else
Me.Textoencontrado = Me.Lista0.ListCount - 1
Tot_Reg = DCount("[Id]", "NGS")
Me.textoporcen = (Me.Textoencontrado) * 100 / Tot_Reg
End If
End Sub

Observe como utilizo la propiedad TAG (Información adicional ), en donde debe ir el nombre del campo.  Si no va a filtrar por rango de fechas comente estas líneas.

CÓDIGO DEL BOTON PARA QUITAR TODOS LOS FILTROS

Private Sub btnQuitaFiltro_Click()
    Dim ctrl As Control
    For Each ctrl In Me.Controls
      If ctrl.ControlType = acComboBox Then
         ctrl = ""
      End If
    Next
    Me.Lista0.RowSource = ""
    Me.Lista0.ColumnHeads = False
    Me.Textoencontrado = ""
    Me.textoporcen = ""
    

Observe como se reduce el código en un 50%, imagínese que fueran 60 controles...

Si quiere los cambios escríbame a [email protected] y se lo hago llegar.

Estimado Eduardo,

En primer lugar disculparme porque no vi su primer mensaje, de ahí que no le haya respondido. Gracias por su ayuda, Estaría encantado si pudiera hacerme llegar la base de datos a mi dirección [email protected] Y a partir de ahí ya le comento al respecto de las modificaciones que implementado.

Gracias!

Le envíe la base de datos a su correo y a la nube por WeTransfer .

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas