Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Busqueda en la BD a partir de un texto tecleado (https://www.clubdelphi.com/foros/showthread.php?t=94342)

Gregorio Cíber 17-12-2019 10:09:06

Busqueda en la BD a partir de un texto tecleado
 
Hola amigos.
El siguiente código lo utilizo para seleccionar registros dentro de una tabla contenida en una TDBGrid y situarnos en la primera coincidencia.

Dos controles: edt_TablaBuscar (TEdit) y box_TablaBuscar (TComboBox). Este último con ITems = '','Empieza', 'Contiene', 'Termina'.

A medida que se escribe en edt_TablaBusca se ejecuta edt_TablaBuscarChange y si se cambia la propiedad Item de box_TablaBuscar se ejecuta box_TablaBuscarChage. La variable UltimoCampo contiene el campo por el que se busca. Se asigna a partir del TDBGrid cuando se pincha en titulo.

Código Delphi [-]
procedure edt_TablaBuscarChange(Sender: TObject);
var
  f : TDate;
  s : String;
begin
  inherited;

  s := edt_TablaBuscar.Text;

  try
    tbl_Tabla.Locate( UltimoCampo,
                      VarArrayOf([ UpperCase(s) ]),
                      [loCaseInsensitive, loPartialKey] );
    box_TablaBuscarChange(Sender);
  except
    try
      f := StrToDate(s); //StrToDate(edt_TablaBuscar.Text);
      tbl_Tabla.Locate( UltimoCampo,
                        f,
                        [loCaseInsensitive, loPartialKey] );
    except
      //
    end;
  end;
end;


procedure TfP__BaseAC_Tabla_B.box_TablaBuscarChange(Sender: TObject);
var
  s: string;
begin
  inherited;

  case box_TablaBuscar.ItemIndex of
    0: s := '';
    1: s := edt_TablaBuscar.Text + '%';
    2: s := '%' + edt_TablaBuscar.Text + '%';
    3: s := '%' + edt_TablaBuscar.Text;
  end;
  s := UpperCase(s);
  //
  if box_TablaBuscar.ItemIndex > 0 then
    s := '(' + UltimoCampo + ' IS NOT NULL) ' +
         'AND ' +
         '(UPPER (' + UltimoCampo + ') LIKE ''' + s + ''')';
  //
  try
    tbl_Tabla.Filter   := s;
    tbl_Tabla.Filtered := (box_TablaBuscar.ItemIndex > 0);
  except
    //tbl_Tabla.Filtered := False;
    //box_TablaBuscar.ItemIndex := 0;
  end;
  //
  ActiveControl := grd_Tabla;
end;

Hasta aqui todo bien. El código funciona y, aunque estoy pensado en algunas mejoras, no me ha dado problemas a lo largo del tiempo.

Sin embargo adolece de un defecto y es que la tabla debe estar cargada en memoria, lo cual es un proble cuando hay decenas o centenares de miles de registros. Y aquí va la pregunta, ¿cómo prodría hacerse algo parecido pero tirando de la BD directamente?. Es decir, pidiéndole a Firebird que devuelva las fihas que cumplan las condiciones indicadas en cada caso, teniendo en cuenta que debe valer para cualquier tabla y para cualquier campo de ella.

Gracias anticipadas.

ecfisa 17-12-2019 16:27:57

Hola.
Cita:

Empezado por Gregorio Cíber (Mensaje 534812)
¿cómo prodría hacerse algo parecido pero tirando de la BD directamente?.

Revisa en los enlaces al fin de esta página y en estos,Vas a encontrar mas material buscando por los términos "busqueda incremental" (sin las "").

Saludos. :)

Gregorio Cíber 17-12-2019 16:37:41

Gracias ecfisa. Lo miraré ahora mismo.

Neftali [Germán.Estévez] 18-12-2019 12:01:37

Empezaré respondiendo la última.

Cita:

Empezado por Gregorio Cíber (Mensaje 534812)
¿cómo prodría hacerse algo parecido pero tirando de la BD directamente?.

Utilizando SQL. Puedes lanzar la búsqueda directamente sobre la Base de Datos generanso la sentencia SQl al vue4lo y ejecutándola.

Cita:

Empezado por Gregorio Cíber (Mensaje 534812)
Sin embargo adolece de un defecto y es que la tabla debe estar cargada en memoria, lo cual es un problema cuando hay decenas o centenares de miles de registros.

Ese es el gran problema aquí(a mi entender).
Ya lo he comentado otras veces. El comportamiento que estás utilizando corresponde a una Base de Datos "local" o de "escritorio". Las que usábamois antiguamente y en las que todos los datos se cargaban en memoria. Podías recorrer todos los datros para hacer búsquedas y era cómodo realizar búsquedas "a medida que el usuario iba escribiendo" (porque todos los datos estaban en memoria).

Hoy en día que trabajamos con SGBD's (Servidores de Bases de Datos) no con Bases de Datos de escritorio este comportamiento no es óptimo. Justo por lo que comentas:

(1) Porque para hacerlo debes cargar TODOS los datos en memoria, cosa que puede ser muy ineficiente.
(2) Porque estás generando muuucho más tráfico del necesario.
(3) porque estás sobrecargando el servidor más de lo necesario.

Si alguien quiere buscar por valores que empiezen por "Barcel", por ejempo, al escribir ese texto, estará realizando 6 búsquedas (B, Ba, Bar, Barc, Barce y Barcel) cuando realmente sólo le interesa la última. Ya no digo nada si el usuario es torpe escribiendo y entre medio escribe 2 letras mal, luego las borra y las vuelve a escribir :(:(:(.

Cita:

Empezado por Gregorio Cíber (Mensaje 534812)
A medida que se escribe en edt_TablaBusca se ejecuta edt_TablaBuscarChange...

En estos casos lo habitual es sólo ejecutar la búsqueda sólo al final (o sólo cuando el usuario lo especifica). Por ejemplo, cuando se detecta un ENTER, cualndo el usuario pulsa el botón,... (hay mil maneras)
Ejecutar la búsqueda de forma explícita por el usuario.

Gregorio Cíber 19-12-2019 08:02:29

Gracias Neftalí.


Efectivamente, no es nada eficiente la búsqueda en la BD con cada pulsación de tecla cuando las tablas no está cargadas en memoria. Ya estaba mirando la posibilidad que comentas, me refiero a lanzar la búsqueda en un determinado momento, pero antes de cambiar nada quería tener la seguridad de que no había otra forma de hacerlo que desconocía, sobre todo cuando tienes que 'lidiar' con todo tipo de usuario: los que comprenden que se introduzcan cambios y los que no lo harán nunca.



Gracias.


La franja horaria es GMT +2. Ahora son las 11:53:51.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi