Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Encontrar aniversarios (https://www.clubdelphi.com/foros/showthread.php?t=77855)

Angel.Matilla 01-03-2012 11:55:40

Encontrar aniversarios
 
Buenos días a todos.

Mediante una consulta SQL con tablas Paradox necesito encontrar todas las filas de una tabla en las que su fecha de cumpleaños esté comprendida entre dos dadas que no tienen que ser necesariamente del mismo mes, por ejemplo del 28 de febrero al 2 de marzo. Cuando es una sola fecha no tengo problemas:
Código SQL [-]
SELECT * FROM 'Personas.db' 
WHERE EXTRACT(MONTH FROM F_nacimiento) = Mes AND EXTRACT(DAY FROM F_nacimiento) = Dia

Pero ¿cómo podría hacer la consulta cuando son fechas como en el caso que pongo?

duilioisola 01-03-2012 14:04:31

LA forma más sencilla es:
Código SQL [-]
SELECT * FROM 'Personas.db' 
WHERE 
F_nacimiento >= ?DesdeFecha and 
F_nacimiento <= ?HastaFecha

Angel.Matilla 01-03-2012 17:30:11

Cita:

Empezado por duilioisola (Mensaje 426588)

Código SQL [-]

SELECT * FROM 'Personas.db'
WHERE
F_nacimiento >= ?DesdeFecha and
F_nacimiento <= ?HastaFecha

No me vale, y no porque la idea sea mala. Yo tengo dos fechas, por ejemplo las que citaba antes; pero con la estructura que indicas sólo encontraría las del AÑO que se indicara en la fecha y yo necesito sacar las fichas de los cumplen años entre dos fechas de este año independientemente del año de nacimiento.

Caral 01-03-2012 18:09:21

Hola
A ver asi:

Código SQL [-]
select * From  'Personas.db'
where extract(month from F_nacimiento) >= :mesini and extract(month from F_nacimiento) <= :mesfin
and extract(Day from F_nacimiento) >= :diaini and extract(Day from F_nacimiento) <= :diafin

Saludos

roman 01-03-2012 18:20:17

Una aproximación:

Código SQL [-]
select * from 'personas.db'
where
  31*extract(month from F_nacimiento) + extract(day from F_nacimiento) between 31*:mes_i + :dia_i and 31*:mes_f+ :dia_f

Multiplicar el mes por 31 es necesario para los casos en que el día inicial es mayor que el final aunque el mes inicial se menor. Lo malo es que no sirve para intervalos de fechas que crucen el cambio de año.

// Saludos

marcoszorrilla 01-03-2012 21:46:30

Algo parecido hago yo:

Código Delphi [-]
procedure TfrAniversarios.FormActivate(Sender: TObject);
begin
DecodeDate(Date,aa,mm,dd);
DmClientes.IBDtsCli.Close;
DmClientes.IBDtsCli.SelectSQL.Clear;
DmClientes.IBDtsCli.SelectSQL.Add('Select * From Alumnos ');
DmClientes.IBDtsCli.SelectSQL.Add('Where Baja=''N''');
DmClientes.IBDtsCli.SelectSQL.Add('And Extract(Month from Fnacimiento)= :M');
DmClientes.IBDtsCli.SelectSQL.Add('And Extract(Day from Fnacimiento)  = :D ');
DmClientes.IBDtsCli.ParamByName('M').AsString:=FormatFloat('00',mm);
DmClientes.IBDtsCli.ParamByName('D').AsString:=FormatFloat('00',dd);

DmClientes.IBDtsCli.Open;

end;
Un Saludo

Delphius 01-03-2012 23:21:01

A como lo entiendo, la consulta de Caral debería dar los resultados correctos.
A la propuesta de roman no la he probado pero resulta interesante su forma.

Saludos,

roman 02-03-2012 00:05:15

Cita:

Empezado por Delphius (Mensaje 426639)
debería dar los resultados correctos.

Esta consulta:

Código SQL [-]
select * From  'Personas.db'
where
  extract(month from F_nacimiento) >= :mesini and extract(month from F_nacimiento) <= :mesfin and
  extract(Day from F_nacimiento) >= :diaini and extract(Day from F_nacimiento) <= :diafin

no da resultados correctos. Vamos a aterrizar con unos datos específicos: 28 de febrero y 2 de marzo, que son los que ejemplifica Angel.Matilla.

La consulta queda así:

Código SQL [-]
select * From  'Personas.db'
where
  extract(month from F_nacimiento) >= 2 and extract(month from F_nacimiento) <= 3 and
  extract(Day from F_nacimiento) >= 28 and extract(Day from F_nacimiento) <= 2

Para F_nacimiento = 1 de marzo nos queda:

Código SQL [-]
select * From  'Personas.db'
where
  3 >= 2 and 3 <= 3 and
  1 >= 28 and 1 <= 2

La condición del primer renglón se cumple, mas no así la del segundo. Y sin embargo, el 1 de marzo sí está entre el 28 de febrero y el 2 de marzo.

// Saludos

Delphius 02-03-2012 02:37:08

Pues hoy no le doy a nada :o ... ¡mi cabeza está muy apagada!

Tienes razón roman. ¿Y quizá tal vez no sería más apropiado evaluar sólo en cuanto al mes?

Saludos,

Angel.Matilla 02-03-2012 08:12:54

Gracias a todos por las rspuestas. Voy por partes. En la propuesta de roman no entiendo lo de multiplicar por 31 el mes. En todo caso ¿No sría más lógico multiplicarlo por 100? Desa forma se formarían series desde 101 (1 de enero) al 1231 (31 de diciembre). Esta no se me había ocurrido y la tengo que probar.

La de marcoszorrilla es similar a la primera que me sugirieron pero, al igual que aquella, sólo extrae una fecha de todas las posibles.

Angel.Matilla 02-03-2012 08:22:11

Confirmado. El código ha quedado así:
Código SQL [-]
SELECT * FROM 'Personas.db' 
WHERE 100 * EXTRACT(MONTH FROM F_nacimiento) + EXTRACT(DAY FROM F_nacimiento) BETWEEN 100 * Mes_ini + Dia_ini AND 100 * Mes_fin + Dia_fin AND F_nacimiento != '12/30/1899'

Esa fecha final es porque en las tablas Paradox si una fecha se graba vacía por defecto pone el 30 de diciembre de 1788.

roman 02-03-2012 16:11:49

Cita:

Empezado por Angel.Matilla (Mensaje 426663)
En la propuesta de roman no entiendo lo de multiplicar por 31 el mes. En todo caso ¿No sría más lógico multiplicarlo por 100?

Bueno, en realidad puedes multiplicarlo por 1000 o por 1000000. La idea es simplemente "agrandar" la parte del mes lo suficiente como para que la parte del día no domine en la comparación. De hecho, originalmente usé 100, pero en realidad 31 es suficiente. Es más, creo que 30 es suficiente :p

De todas formas, recuerda que este método va a fallar si, por ejemplo, quieres saber todos los cumpleaños entre el 28 de ciciembre y el 4 de enero.

// Saludos

Delphius 02-03-2012 18:21:10

Para las fechas que "cruzan" de año, como el ejemplo de roman no queda más remedio que armar una condición del tipo:

Código SQL [-]
((:Mes >= Mes_ini) AND (:Mes <= 12)) OR ((:Mes >= 1) AND (:Mes <= Mes_fin))

De este modo se mostrarán aquellas fechas que sean desde el mes "inicial" hasta diciembre inclusive, más las fechas que sean de enero hasta la fecha "final".

Un criterio similar se puede, y debe, llevar a cabo con el tema los días "cruzados" ;)

La cuestión es que ahora la lógica pasa por armar esta condición aplicando una evaluación previa de si el mes final es menor al inicial; y lo mismo aplica para el día.

Saludos,

roman 02-03-2012 22:31:58

Bueno, se supone que todo mes es menor o igual que 12 y mayor o gual que 1, por lo que esos dos condicionales sobrarían.

Lo de la evaluación previa, creo que podemos hacerla en la misma consulta comparando los parámetros en sí:

Código SQL [-]
select * from personas
where
  ( 
    (100*:mi + :di < 100*:mf + :df) and
    (
      (100*:mi + :di < 100*extract(month from fecha) + extract(day from fecha)) and
      (100*extract(month from fecha) + extract(day from fecha) < 100*:mf + :df)
    )
  )
  or
  (
    (100*:mi + :di > 100*:mf + :df) and
    (
      (100*:mi + :di < 100*extract(month from fecha) + extract(day from fecha)) or
      (100*extract(month from fecha) + extract(day from fecha) < 100*:mf + :df)
    )
  )

Un ejemplo de uso:

Código Delphi [-]
var
  mi, mf, di, df: Integer;

begin
  Query1.ParamByName('mi').AsInteger := MonthOf(DateTimePickerInicial.Date);
  Query1.ParamByName('di').AsInteger := DayOf(DateTimePickerInicial.Date);

  Query1.ParamByName('mf').AsInteger := MonthOf(DateTimePickerFinal.Date);
  Query1.ParamByName('df').AsInteger := DayOf(DateTimePickerFinal.Date);

  Query1.Open;
end;

Conste que puse 100 para que no se extrañen :p.

No la he probado del todo pero creo que funciona salvo porque me falta el caso de que las fechas inicial y final sean iguales, pero no debe ser mayor problema.

// Saludos

Angel.Matilla 03-03-2012 16:14:33

¿Ves? Eso no se me había ocurrido, lo de "agrandar" la parte del mes usando una cifra diferente de 100.

El otro problema, el del salto de año (p.ej.: del 28/12/2012 al 04/01/2013) en parte lo soluciono no permitiendo al operador que introduzca fechas superiores al 31 de diciembre del año en curso, pero es cierto que no es la mejor solución y hasta que vea otra opción...

roman 05-03-2012 16:02:47

Cita:

Empezado por Angel.Matilla (Mensaje 426769)
El otro problema, el del salto de año (p.ej.: del 28/12/2012 al 04/01/2013)

Bueno, se supone que la última consulta que puse resuelve eso. ¿La has probado?

// Saludos

Angel.Matilla 07-03-2012 10:48:52

Cita:

Empezado por roman (Mensaje 426873)
Bueno, se supone que la última consulta que puse resuelve eso. ¿La has probado?

// Saludos

Sí, lo probé pero con el código que puse yo también pude resolverlo. Gracias Roman.


La franja horaria es GMT +2. Ahora son las 10:32:21.

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