Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   Filtrado de una tabla. (https://www.clubdelphi.com/foros/showthread.php?t=2453)

fortran 24-07-2003 10:58:29

Filtrado de una tabla.
 
A ver si me podeis echar una mano porque en esto estoy más perdido que un pulpo en un garage.

Utilizo wxp y D5 y las tablas son Paradox.

Os cuento, tengo dos tablas en mi aplicación.
1.- TablaClientes.
2.- TablaVisitas.

En un formulario quiero que al seleccionar un cliente en un DBGrid me salgan las fechas de sus visitas (en otro dbgrid), hasta ahí bien, he hecho un maestro-detalle. Ahora lo que quiero es que al seleccionar una fecha de las que salen en el dbgrid me salgan los servicios realizados en esa fecha. Para ello puse un memo en el que volcaré los datos que encuentre para os servicios de esa fecha.

El volcado no me supone problema, el problemasurge porque quiero filtrar por fecha del siguiente modo:

Código PHP:

procedure TFormularioPrincipal.DBGridVisitasCellClick(ColumnTColumn);
begin
   modulodedatos
.tablavisitas.filter := 'FechaVisita = '
            
column.Field.AsString;
   
modulodedatos.tablavisitas.Filtered := TRUE;
   
rellenardatoscliente// es para cargar el memo
end

Bueno, pues cuando ejecuto el programo y hago click en una fecha me salta una excepción que dice:

EdatabaseError with message 'Arithmetic in filter expresions not supported'. ¿Como puedo solucionar esto?.
¿Sería mejor que buscase otra solución?.

Un saludo y gracias por vuestra atención.

Cabanyaler 24-07-2003 14:02:07

Bueno, en primer lugar yo te aconsejaria que trabajases o bien con consultas o vistas en lugar de con filtros, verás que mejoras el rendimiento y velocidad y disminuyes el tmp de respuesta del sistema.

Luego, creo que te falta mencionar que para los servicios tienes otra tabla ¿no?, la cual se encuentra relacionada en maestro:detalle con la tabla de visitas. Si no es así yo lo diseñaria de ese modo, ya que me parece mejor solución que no el volcarlo a un Memo. (es sólo mi opinión o consejo, vamos...)

En cuanto al error, muy probablemente salte por la naturaleza de los datos en los que estas intentando realizar el filtro, es decir, el
column.Field.AsString quizá es por el forzado de tipo String, mientras que el campo en el que estableces el filtro supongo que lo tendrás declarado como de tipo dateTime. Puede venir por ahí el error, creo yo.

Suerte. :p

__cadetill 24-07-2003 14:13:16

Bueno, te habia respondido al otro hilo que tenias abierto y, luego me he dado cuenta que estaba este, asi que te pongo aqui lo que te habia contestado

Prueba algo asi

Código:

var
  str : string;
begin
  str := 'FechaVisita = ' + QuotedStr(FormatDateTime('mm/dd/yyyy',
                    column.Field.AsDateTime));
  modulodedatos.tablavisitas.filter := str;
  modulodedatos.tablavisitas.filtered := true;
end;

Pero, si no he entendido mal, estas haciendo un master-detail1-detail2, no? Si es asi, puedes hacer que el detail1 sea el master del detail2 y presentar los datos en un TDbGrid, no se si me explico

Bueno, espero te sirva

PD: el formato de fecha dependera del motor de bases de datos que utilices (creo que en Paradox es eso, pero no recuerdo al 100%)

EDIT: para evitar el scroll horizontal

fortran 24-07-2003 17:40:04

Hola a los dos:

Lo primero dar las gracias a Cadetil por cerrar el otro post (que era identico a este), creo que salió repetido porque le di al cabo del tiempo a refrescar la página.

He hecho lo que me dijo Cadetil y funciona, pero no me he quedado muy satisfecho, ya que al hacer el filtro también me desaparecen las otras fechas de visita.

La cuestión es que la tabla de visitas consiste en:

- 1 campo indice_visitas
- 1 campo clave_cliente
- 1 campo fecha_visita
- 7 campos servicio1, servicio2, servicio3, ...

(no es probable que en una visita se hagan más de 7 servicios).

En la tabla de servicios solamente he incluido:

- 1 Campo Clave_servicio
- 1 Campo Nombre_servicio
- 1 Campo Precio_servicio

Y luego tengo la tabla de clientes:

Con la clave_cliente, nombre_cliente...

Tal como lo tengo no puedo hacer un master:detail1:detail2.

¿Se os ocurre otra manera mejor de organizar las tablas?

Lo de hacer una consulta lo he intentado, pero me he liado ¿sabeis de algún sitio donde expliquen bien lo de las consultas?

Un saludo y gracias por vuestras respuestas.

PD: Cadetil, el formato de fecha en Paradox era (dd/mm/yy).

Mick 24-07-2003 23:34:44

Debes crear un indice secundario para el campo fecha_visita en la tabla de visitas, usa el database desktop para ello,
Una vez que tengas el indice definido , supongamos que le has llamado , ifecha_visita, primero tienes que activarlo para la tabla:

Tabla.IndexName:= 'ifecha_visita';

Lo que hara que los registros queden ordenador por el campo del indice (por fecha de visita).

Despues si solo quieres mostrar los registros de esa fecha harias algo como:

Tabla.SetRange( [ FechaInicial],[FechaFinal]);

para Cancelar el rango:

Tabla.CancelRange;

para Desactivar el indice

Table.IndexName:= '';

Pero parece que esta solucion no es la que te interesa, lo que quieres hacer es que se muestren todos los registros pero posicionarte en los de determinada fecha para ello haces algo como:

Tabla.FindNeares([FechaABuscar]);

La ventaja de usar indices, es que la operaciones sobre las tablas son infinitamente mas rapidas.

Salud2 !!

__cadetill 25-07-2003 16:08:17

Bien, tal y como lo veo, tenemos lo siguiente

Tabla Visitas --> Tabla Clientes con relacion N-->1

Esta relacion no hay problemas (segun comentas en tu primer post). Solo un comentario, el indice de la tabla visitas tendria que ser

ID_Cliente
ID_Visita

Siempre ha de ir el indice de la tabla maestra al principio y luego el indice de la detalle.

Ok, ya tenemos la relacion hecha.

Para la siguienta tebla, Servicios, esta no es un detalle de Visitas. Tal y como yo lo veo (por lo que pones), ésta es un maestro de Servidios que nos informa de qué servicio es y el precio.

Para hacer lo que quieres, es decir, coger la descripcion del servcio y el precio (creo entender que es eso), lo que yo haria es poner campos calculados en tu DataSet de Visitas que recuperaran la informacion que deseas de la tabla de Servicios

Es eso lo que quieres?

Ya nos contaras, espero te sirva

fortran 28-07-2003 09:47:40

He hecho tal y como decía Cadetill:

TablaClientes --> TablaVisitas, y hasta ahí bien.

Para acceder al servicio que se ha hecho al tener el código he hecho lo siguiente:

Código:

Procedure RellenarDatosCliente;
Var
  i : integer;
  indicedeservicios:  array [1..7] of integer;
Begin
with FormularioPrincipal do
Begin
// recogida de indices de servicios
  indicedeservicios[1]:= modulodedatos.tablavisitasserviciorealizado1.value;
  indicedeservicios[2]:= modulodedatos.tablavisitasserviciorealizado2.value;
  indicedeservicios[3]:= modulodedatos.tablavisitasserviciorealizado3.value;
  indicedeservicios[4]:= modulodedatos.tablavisitasserviciorealizado4.value;
  indicedeservicios[5]:= modulodedatos.tablavisitasserviciorealizado5.value;
  indicedeservicios[6]:= modulodedatos.tablavisitasserviciorealizado6.value;
  indicedeservicios[7]:= modulodedatos.tablavisitasserviciorealizado7.value;
// Localización en la tabla de servicios de esos índices e inserción del nombre en
// el Memo1
  for i := 1 to 7 do
  Begin
  with modulodedatos.tablaserviciosclaveservicio do
  Begin
      modulodedatos.TablaServicios.First;
      While not eof do
        if value = indicedeservicios[i] then
            memo1.lines[i] := modulodedatos.TablaServiciosnombreservicio.Value
        else
            Next;
    End;
    End;
End;
End;

El problema es que me da un Class EInOutError con mensaje(I/O error 6). En la sentencia while not eof do. ¿por que?.

__cadetill 28-07-2003 11:24:53

Cita:

Posteado originalmente por fortran

While not eof do

sustituyelo por

Código:

modulodedatos.tablaserviciosclaveservicio.Eof
El with que haces, es sobre un TField, no sobre la tabla, de ahi el error ese, ya que tambien existe el EOF como funcion.

De todas maneras, desde mi punto de vista, el codigo que has puesto no es muy eficiente. Podrias mirar de sustituirlo por algo asi (que quizas no da tantas vueltas a la tabla)

Código:

var Q: TQuery;
begin
  Q := TQuery.Create(Self);
  Q.DatabaseName := modulodedatos.TablaServicios.DatabaseName;
  Q.SQL.Text := 'select nombreservicio from TablaServicios where claveservicio = :valor';
  try
    // primero
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado1.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // segundo
    Q.Close;
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado2.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // tercero
    Q.Close;
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado3.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // ........
  finally
    FreeAndNil(Q);
  end;
end;


fortran 28-07-2003 17:51:29

Hola Cadetill.
He intentado las dos soluciones, vaya por delante que me parece más correcta la segunda. Pero ninguna la he podido llegar a concluir. En la primera me dice:
[Error] UtilidadesAplicacion.pas(28): Undeclared identifier: 'eof'

En el segundo caso (que es el que me gustaría implementar) no soy capaz de conseguir que me acepte el self:

Me sale
[Error] UtilidadesAplicacion.pas(52): Undeclared identifier: 'Self'.

__cadetill 28-07-2003 19:52:40

Veamos

Para la primera, mea culpa, hice un cortar y pegar y asi me feu :p

Tendria que haber sido

Código:

modulodedatos.tablaservicios.Eof
Osea, el EOF pertenece al DataSet, no al Field :D

La segunda opcion. No se donde estaras haciendo el Create (Form, DataModule,...), pero si no te acepta el Self, prueba Application (que esta definido en la unit Forms)

Espero te sirva ;)

fortran 29-07-2003 17:02:31

Hola Cadetill:

Lo primero decirte que la primera opción funcionó perfectamente, con la modificación que me dijiste y alguna más, para solucionar una metedura de pata que tenía en el código que hacía que no terminara nunca el bucle con while. Con la segunda me pongo ahora a ver si doy con la solución, de momento he de decirte que es un procedimiento que tengo en una unidad, en ningún formulario.

P.D.

El código de la primera opción (la mala) quedaría así:

Código:

Procedure RellenarDatosCliente;
Var
  i : integer;
  indicedeservicios:  array [1..7] of integer;
Begin
with FormularioPrincipal do
Begin
  for i := 1 to 7 do
  memo1.Lines[i]:= '';
 
// recogida de indices de servicios
  indicedeservicios[1]:= modulodedatos.tablavisitasserviciorealizado1.value;
  indicedeservicios[2]:= modulodedatos.tablavisitasserviciorealizado2.value;
  indicedeservicios[3]:= modulodedatos.tablavisitasserviciorealizado3.value;
  indicedeservicios[4]:= modulodedatos.tablavisitasserviciorealizado4.value;
  indicedeservicios[5]:= modulodedatos.tablavisitasserviciorealizado5.value;
  indicedeservicios[6]:= modulodedatos.tablavisitasserviciorealizado6.value;
  indicedeservicios[7]:= modulodedatos.tablavisitasserviciorealizado7.value;
// Localización en la tabla de servicios de esos índices e inserción del nombre en
// el Memo1
  for i := 1 to 7 do
  Begin
  with modulodedatos.tablaservicios do
  Begin
      modulodedatos.TablaServicios.First;
      While not eof do
        if modulodedatos.TablaServiciosClaveServicio.value = indicedeservicios[i] then
        Begin
            memo1.lines[i] := modulodedatos.TablaServiciosnombreservicio.Value;
            next;
        end
        else
            Next;
    End;
    End;
    For i := 1 to 7 do
    If memo1.Lines[i] = '0' then
      memo1.lines[i] := ''
End;
End;


__cadetill 29-07-2003 17:29:39

Cita:

Posteado originalmente por fortran
Con la segunda me pongo ahora a ver si doy con la solución, de momento he de decirte que es un procedimiento que tengo en una unidad, en ningún formulario.

Ok, por eso no te funciona el Self. Prueba lo que te comento de añadir Forms en el uses y utilizar Application


Cita:

Posteado originalmente por fortran
Código:

      While not eof do begin
        if modulodedatos.TablaServiciosClaveServicio.value = indicedeservicios[i] then
        Begin
            memo1.lines[i] := modulodedatos.TablaServiciosnombreservicio.Value;
            next;
        end
        else
            Next;
    End;


Respecto a este cacho de codigo, no crees que es lo mismo que hacer...
Código:

      While not eof do begin
        if modulodedatos.TablaServiciosClaveServicio.value = indicedeservicios[i] then
            memo1.lines[i] := modulodedatos.TablaServiciosnombreservicio.Value;
          Next;
    End;

y nos ahorramos alguna linea ;) Ya que, sea cual sea el resultado de la condicion del IF vamos ha hacer un Next, podemos quitarlo de dentro del mismo

fortran 29-07-2003 18:24:45

Tienes toda la razón nos ahorramos un par de líneas.

Con respecto a lo del application no he dado con ello. Probablemente porque no se la sintaxis que debo poner.
He probado varias cosas con distintos resultados (pero todos negativos) :confused: . He probado a poner

Q:= application.create(TQuery);

y me dice:
[Error] UtilidadesAplicacion.pas(56): Incompatible types: 'TComponent' and 'Class reference'

También he probado:

Q:= application.create(self);

y me dice:

[Error] UtilidadesAplicacion.pas(56): Undeclared identifier: 'self'

__cadetill 29-07-2003 20:09:17

cuando te decia que en lugar de Self utilizaras Application, me referia a algo asi

Q := TQuery.Create(Application);

A ver ahora que tal ;)

fortran 01-08-2003 11:32:41

Hola de nuevo Cadetill:

He tardado en responder porque he "pescado" un gripazo que me ha tenido en cama 2 días.

La solución que me propusiste funcionó a la perfección, solamente le añadí al principio del procedimiento una línea para borrar el memo1 antes de iniciar.

Por si a alguien le puede servir dejo aquí el código final.

Código:

Procedure RellenarDatosCliente;

var
Q: TQuery;
begin
with formularioprincipal do
Begin
  memo1.Lines.clear;
  Q := TQuery.create(Application);
  Q.DatabaseName := modulodedatos.TablaServicios.DatabaseName;
  Q.SQL.Text := 'select nombreservicio from TablaServicios where claveservicio = :valor';
  try
    // primero
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado1.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // segundo
    Q.Close;
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado2.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // tercero
    Q.Close;
    Q.ParamByName('valor').Value := modulodedatos.tablavisitasserviciorealizado3.value;
    Q.Open;
    if not Q.Fields[0].IsNull then Memo1.Lines.Add(Q.Fields[0].AsString);
    // ........
  finally
    FreeAndNil(Q);
  end;
End;
end;



Pues muchas gracias Cadetill, me has sido de gran ayuda.


La franja horaria es GMT +2. Ahora son las 21:06:07.

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