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)
-   -   To Be or Not To Be: Filtrar o no Filtrar esa es la cuestion (https://www.clubdelphi.com/foros/showthread.php?t=48748)

gorsan 03-10-2007 11:43:41

To Be or Not To Be: Filtrar o no Filtrar esa es la cuestion
 
Buenos días a todos. Planteo la siguiente cuestión:
En mi aplicación tengo, entre otras muchas cosas, dos tablas

Código SQL [-]
CREATE DOMAIN "AB" AS VARCHAR(1)
   DEFAULT 'A'
   CHECK(VALUE='A' OR VALUE='B');
CREATE DOMAIN "CENTRO_LABORAL" AS VARCHAR(3)
   CHECK(VALUE='PRI' OR VALUE='SEG');
CREATE DOMAIN "DOC_NAL_IDEN" AS INTEGER
   CHECK (VALUE>=1 AND VALUE<=99999999);
CREATE DOMAIN "FECHA_CADUCIDAD" AS TIMESTAMP
   CHECK(VALUE>='NOW');
CREATE DOMAIN "MATRICULA_COCHE" AS VARCHAR(10);
CREATE DOMAIN "NOM" AS VARCHAR(60);
CREATE DOMAIN "OBJETO_ACCESO" AS VARCHAR(20);
CREATE DOMAIN "PRIMER_APELLIDO" AS VARCHAR(60);
CREATE DOMAIN "SEGUNDO_APELLIDO" AS VARCHAR(60);
CREATE DOMAIN "VERDADERO_FALSO" AS CHAR(1)
   DEFAULT 'N'
   CHECK(VALUE='S' OR VALUE='N');

CREATE TABLE "EXTERNOS_DNI" 
(
  "DNI1"  "DOC_NAL_IDEN" NOT NULL,
  "LETRA_NIF"  CHAR(1),
  "APELLIDO_1"  "PRIMER_APELLIDO" NOT NULL,
  "APELLIDO_2"  "SEGUNDO_APELLIDO",
  "NOMBRE"  "NOM" NOT NULL,
  "MATRICULA"  "MATRICULA_COCHE",
  "CENTRO"  "CENTRO_LABORAL" NOT NULL,
  "OBJETO"  "OBJETO_ACCESO",
  "ALTA_BAJA"  "AB",
  "CADUCIDAD"  "FECHA_CADUCIDAD",
  "NOTAS"  BLOB SUB_TYPE TEXT SEGMENT SIZE 80,
  "ESTA_DENTRO"  "VERDADERO_FALSO",
 PRIMARY KEY ("DNI1")
);

Código SQL [-]
CREATE DOMAIN "DOC_NAL_IDEN" AS INTEGER
   CHECK (VALUE>=1 AND VALUE<=99999999);

CREATE TABLE "MOV_EXTERNOS_DNI" 
(
  "DNI2"  "DOC_NAL_IDEN" NOT NULL,
  "DIA_ENTRADA"  TIMESTAMP,
  "DIA_SALIDA"  TIMESTAMP
);
ALTER TABLE "MOV_EXTERNOS_DNI" ADD CONSTRAINT "MOVIMIENTO_DNI" FOREIGN KEY ("DNI2") REFERENCES EXTERNOS_DNI ("DNI1") ON DELETE CASCADE;
ALTER TABLE "MOV_EXTERNOS_DNI" ADD CONSTRAINT "MOVIMIENTO_DNI_2" FOREIGN KEY ("DNI2") REFERENCES EXTERNOS_DNI ("DNI1") ON UPDATE CASCADE;

Éstas están encapsuladas en dos IBDataSet (uso IBX6).
Mediante un IBQuery quiero conseguir un conjunto de datos que luego seran pasados a la impresora para obtener un listado (les ruego si hay otra forma mejor de hacer esto me lo hagan saber). Hasta el momento he intentado de las dos maneras que mas adelante expondré, obtener ese conjunto de datos pero no hay forma. Me explicaré:
Quiero de la tabla MOV_EXTERNOS_DNI obtener solo los registros que se correspondan con un dia determinado. El criterio de union entre los dos conjuntos de datos es DN1=DN2.
Primero he intentado con un filtro en el evento OnFilterRecord del IBQuery lo siguiente:
Código Delphi [-]
procedure TDM.IBQuery1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  Dia: TDateTime;
begin
  DataSet:=DM.IBDS_DNI_MOV;//esta es MOV_EXTERNOS_DNI
  Dia:=DateOf(DM.IBDS_DNI_MOV.FieldByName('DIA_ENTRADA').AsDateTime);
  Accept:=DateTimeToTimeStamp(DataSet['DIA_ENTRADA'])=DateTimeToTimeStamp(Dia);
end;
Pero falla en el subrayado.
Despues he intentado con una consulta en los siguientes términos:
Código SQL [-]
procedure TForm1.FormShow(Sender: TObject);
var
  Dia: String;
begin
 Dia:=DateTimeToStr(Now);
 with DM.IBQuery1 do
   begin
       if Active=True then Active:=False;
       UnPrepare;
       SQL.Clear;
       SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
       SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
       SQL.Add('WHERE DNI1=DNI2 AND '+quotedstr(DM.IBDS_DNI_MOV.FieldByName('DIA_ENTRADA').AsString)+'='+quotedstr(Dia));
       SQL.Add('ORDER BY DNI1');
       Prepare;
       if Active=False then Active:=True;
       Open;
   end;
end;
El resultado de esta consulta es cero registros.
¿Alguien me puede ayudar? Estoy mas perdido que el "banco del arroz".

Gracias a todos.

duilioisola 03-10-2007 11:58:14

Yo creo que la segunda es mejor, pero veo un error: Tu SELECT devuelve lo siguiete:
Si lo que hay en DIA_ENTRADA=01/01/2007
y lo que hay en Dia = 28/09/2007
Código SQL [-]
SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA
FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI
WHERE DNI1=DNI2 AND '01/01/2007'='28/09/2007'
ORDER BY DNI1


Código Delphi [-]
procedure TForm1.FormShow(Sender: TObject);
var
  Dia: String;
begin
 Dia:=DateTimeToStr(Now);
 with DM.IBQuery1 do
   begin
       if Active=True then Active:=False;
       UnPrepare;
       SQL.Clear;
       SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
       SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
       SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA='+quotedstr(Dia));
       SQL.Add('ORDER BY DNI1');
       Prepare;
       if Active=False then Active:=True;
       Open;
   end;
end;

duilioisola 03-10-2007 12:01:51

Una opción que me gusta un poco más es usar parámetros:
Te olvidas de esta manera de tener que dar formato a los campos (QuotedStr, DateTimeToStr, etc...
Código Delphi [-]
procedure TForm1.FormShow(Sender: TObject);
var
  Dia: String;
begin
 Dia:=DateTimeToStr(Now);
 with DM.IBQuery1 do
   begin
       if Active=True then Active:=False;
       UnPrepare;
       SQL.Clear;
       SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
       SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
       SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA=?DIA_ENTRADA'); {Aqui no se si va ? o : delante del nombre del parametro}
       SQL.Add('ORDER BY DNI1');
       {No recuerdo si debe ir entre parentesis o entre corchetes}
       Params.ByName['DIA_ENTRADA'].AsDateTime := Dia;
       Prepare;
       if Active=False then Active:=True;
       Open;
   end;
end;

gorsan 03-10-2007 12:55:03

Sigue igual
 
El siguiente codigo (retocado minimamente respecto al que me has pasado) arroja cero registros y deberia haber alguno:

Código SQL [-]
procedure TForm1.FormShow(Sender: TObject);
var
  Dia: String;
begin
 Dia:=DateTimeToStr(Now);
 with DM.IBQuery1 do
   begin
       if Active=True then Active:=False;
       UnPrepare;
       SQL.Clear;
       SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
       SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
       SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA=?DIA_ENTRADA'); {en lugar de ? debe haber dos puntos}
       SQL.Add('ORDER BY DNI1');
       Params[0].AsString:=Dia;
       Prepare;
       if Active=False then Active:=True;
       Open;
   end;
end;

Creo que saber lo que pasa pero no como arreglarlo. La variable dia es un TDateTime convertido a cadena. Por tanto tiene el siguiente formato:
"01/01/2001 10:00:00" y claro, no coincide por el añadido de la hora. Lo suyo seria eliminar de alguna manera (?) el campo hora de la cadena. ¿Pero como?
Gracias de antemano.

Ivanzinho 03-10-2007 13:05:49

Cita:

Empezado por gorsan (Mensaje 235792)
El siguiente codigo (retocado minimamente respecto al que me has pasado) arroja cero registros y deberia haber alguno:

Código SQL [-]procedure TForm1.FormShow(Sender: TObject);
var
Dia: String;
begin Dia:=DateTimeToStr(Now); with DM.IBQuery1 do begin if Active=True then Active:=False;
UnPrepare;
SQL.Clear;
SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA=?DIA_ENTRADA'); {en lugar de ? debe haber dos puntos}
SQL.Add('ORDER BY DNI1');
Params[0].AsString:=Dia;
Prepare;
if Active=False then Active:=True;
Open;
end;
end;


Creo que saber lo que pasa pero no como arreglarlo. La variable dia es un TDateTime convertido a cadena. Por tanto tiene el siguiente formato:
"01/01/2001 10:00:00" y claro, no coincide por el añadido de la hora. Lo suyo seria eliminar de alguna manera (?) el campo hora de la cadena. ¿Pero como?
Gracias de antemano.

Yo de ti lo almacenaría como un campo Date, pero para el caso que nos ocupa podría valerte los siguiente :

Código Delphi [-]
Dia := 'La_Fecha_Que_Sea%'
UnPrepare; 
SQL.Clear;SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA like :DIA_ENTRADA'); 
SQL.Add('ORDER BY DNI1');
Params[0].AsString:=Dia;
Prepare;
if Active=False then 
   Active:=True;
Open;
Un saúdo

duilioisola 03-10-2007 14:52:45

Lo malo de tratarlo como un string, son las conversiones. (dd/mm/yyyy, mm/dd/yyyy, etc.)

Puedes tratar de la siguiente manera:
Dia será del tipo TDateTime.
Trunc(Dia) devuelve la fecha sin hora.

Código Delphi [-]
procedure TForm1.FormShow(Sender: TObject);
var
  Dia: TDateTime;
begin
   {Dia:=DateTimeToStr(Now);}
   with DM.IBQuery1 do
   begin
       if Active=True then Active:=False;
       UnPrepare;
       SQL.Clear;
       SQL.Add('SELECT DNI1, LETRA_NIF, APELLIDO_1, APELLIDO_2, NOMBRE, MATRICULA, CENTRO, OBJETO, DNI2, DIA_SALIDA, DIA_ENTRADA');
       SQL.Add('FROM EXTERNOS_DNI, MOV_EXTERNOS_DNI');
       SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA >= :DESDE_ENTRADA AND DIA_ENTRADA < :HASTA_ENTRADA');
       SQL.Add('ORDER BY DNI1');
       Params[0].AsDateTime:=Trunc(Dia);
       Params[1].AsDateTime:=Trunc(Dia+1);
       Prepare;
       if Active=False then Active:=True;
       Open;
   end;
end;

gorsan 03-10-2007 15:58:36

Para duilioisola
 
No entiendo bien el código que me pones:
Código Delphi [-]
SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA >= ESDE_ENTRADA AND DIA_ENTRADA < :HASTA_ENTRADA');
¿Podias ser mas explicito? Muchas gracias por tu tiempo.

Lepe 03-10-2007 16:17:35

Estarás harto de usar procedimientos con parámetros de entrada ¿verdad? Por ejemplo cuando usas combo.Items.Add('un elemento más'), estas usando un parámetro de tipo texto que se lo das al método "Add". Pues eso mismo se hace aquí pero, con un TIBQuery.

En realidad, el código where debe aparecer así: (sin los emoticones jejeje):
Código Delphi [-]
SQL.Add('WHERE DNI1=DNI2 AND DIA_ENTRADA >= :DESDE_ENTRADA AND DIA_ENTRADA < :HASTA_ENTRADA');

Cuando antepones los dos puntos ":" a un nombre, éste se convierte en un parámetro de entrada, que después se asigna su valor con:
Código Delphi [-]
 Params[0].AsDateTime:=Trunc(Dia);
 Params[1].AsDateTime:=Trunc(Dia+1);

o bien:
Código Delphi [-]
 ParamByName('DESDE_ENTRADA').AsDateTime:=Trunc(Dia);
 ParamByName('hasta_entrada').AsDateTime:=Trunc(Dia+1);

Aquí se ha usado DESDE_ENTRADA y HASTA_ENTRADA, pero puedes poner el nombre que te venga en gana, siempre que no sea igual a una palabra reservada de SQL o nombre de un campo (eso ya es otra historia ;)).

¿Ventajas?
- Al usar parámetros el SQL queda compilado, las sucesivas ejecuciones son más rápidas, precisamente porque la expresion SQL no ha de evaluarse de nuevo.

- Delphi se encarga de las conversiones de fechas (por ejemplo), ten en cuenta que paradox, Firebird, Oracle, etc pueden usar configuraciones de fecha distintas dd/mm/yyyy o bien mm/dd/yyyy o bien yyyy/mm/dd.

Saludos

duilioisola 03-10-2007 16:28:35

Una cosa más sobre la explicación que te han dado:

Si Dia = 03/10/2007 16:21
Trunc(Dia)=03/10/2007
Trunc(Dia+1)=04/10/2007

El WHERE del SQL hace que 03/10/2007 <= DIA_ENTRADA < 04/10/2007.
- O dicho de otra manera: que DIA_ENTRADA esté comprendido entre 03/10/2007 y 04/10/2007.
- O dicho de otra manera diferente: todas las horas del día 03/10/2007.

Nota:
- al poner >= 03/10/2007 tomará todo lo mayor que el 03/10/2007 y este incluido.
- al poner < 04/10/2007, tomará todo hasta el 04/10/2007 pero sin el 04/10/2007. O sea hasta el 03/10/2007 23:59:59

duilioisola 03-10-2007 16:47:25

Si, creo que funcionará.
Desde cualquier ip por el puerto 9923 enviarlo a la IP 192.168.0.129 puerto 9923.
Esto tendrás que ponerlo en el router del PC2 (al que te conectas)

gorsan 04-10-2007 11:14:10

Me ha quedado muy claro
 
Muchas gracias. Algo nuevo que he aprendido.
Gracias a todos por vuestras respuestas y vuestro tiempo.


La franja horaria es GMT +2. Ahora son las 00:02:13.

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