Interseccion de fechas

30/07/2004 - 18:07 por SRenau | Informe spam
Hola,

El problema es el siguiente, tengo una tabla con 3 campos
id, fecha_inicio, fecha_fin.

Desearia obtener las fechas para las cuales
hay "solapamiento" de dias y me cuente el numero de
registros que intervienen.

Ejemplo:

id f_inicio f_fin
1 01/07/2004 09/07/2004
2 06/07/2004 15/07/2004
3 18/07/2004 22/07/2004
4 01/08/2004 09/08/2004
5 04/08/2004 05/08/2004
6 05/08/2004 19/08/2004
7 11/09/2004 09/09/2004

Resultado

count f_inicio f_fin
2 06/07/2004 09/07/2004
3 05/08/2004 05/08/2004

Es dificil de explicar asi que si hay dudas preguntar.

Gracias.

Preguntas similare

Leer las respuestas

#6 SRenau
04/08/2004 - 18:27 | Informe spam
Hola de nuevo, y de nuevo gracias por el interes te has
pegado una buena currada.

Tengoq ue adentrar más, pero yo ya tantee esta posibilidad
en su dia y la complagidad de las tablas que "realmente"
necesito emplear me supondrian unos 100 millones de
consultas para testear todas las posibilidades para cada
dia.

Esto supongo que no sera muy practico, pero le voy ha dar
unas cuantas vueltas a tu "exposicion" a ver si me orienta
en un mejor camino.


Hola:
El problema es bien complejo y tiene mas


implicaciones de Logica que de
SQL.
Antes de empezar, me parece hay dos errores.
a) La fila 7, la columna f_fin no debe ser 09/09/2004 ya


que terminaria
antes de empezar, asi que asumo que es un error. Asumo


que la fecha seria
19/09/2004
b) El resultado de los conflictos no esta completo, ya


que el dia
04/08/2004, hay conflicto entre la fila 4 y la fila 5.


Adicionalmente del
dia 06/08/2004 al dia 09/08/2004 entre la fila 4 y 6.
Entonces el Resultado de los conflictos deberia ser asi:
count f_inicio f_fin
-
2 06/07/2004 09/07/2004
2 04/08/2004 04/08/2004
3 05/08/2004 05/08/2004
2 06/08/2004 09/08/2004
=>Si esto es correcto, entonces hay varias alternativas


para encontrar este
conjunto de resultados. Estuve analizando 2 caminos, el


mas "sencillo" es de
ayudarse de una Tabla de Fechas.
Basados en el siguiente Esquema:
=>SET NOCOUNT ON
GO
CREATE TABLE RangosFechas(
RangoId INT NOT NULL
PRIMARY KEY
, F_Inicio SMALLDATETIME NOT NULL
CHECK(DATEPART(Hour, F_Inicio)=0
AND DATEPART(Minute, F_Inicio)=0)
, F_Fin SMALLDATETIME NOT NULL
CHECK(DATEPART(Hour, F_Fin)=0
AND DATEPART(Minute, F_Fin)=0)
, CONSTRAINT CH_RangosFechasInicioMenorFin
CHECK(F_Inicio<F_Fin)
)

INSERT RangosFechas(RangoId, F_Inicio, F_Fin)
SELECT 1, '2004/07/01','2004/07/09' UNION ALL
SELECT 2, '2004/07/06','2004/07/15' UNION ALL
SELECT 3, '2004/07/18','2004/07/22' UNION ALL
SELECT 4, '2004/08/01','2004/08/09' UNION ALL
SELECT 5, '2004/08/04','2004/08/05' UNION ALL
SELECT 6, '2004/08/05','2004/08/19' UNION ALL
SELECT 7, '2004/09/11','2004/09/19'

CREATE TABLE FechasHlp(
Fecha SMALLDATETIME
NOT NULL PRIMARY KEY
CHECK(DATEPART(Hour, Fecha)=0
AND DATEPART(Minute, Fecha)=0)
)
GO
DECLARE @Fecha SMALLDATETIME
SET @Fecha='2004/01/01'

WHILE @Fecha<'2005/01/01'
BEGIN
INSERT FechasHlp
VALUES (@Fecha)
SET @FechaÚTEADD(day,1,@Fecha)
END
=> La tabla de FechasHlp es muy util para hacer este


tipo de consultas, en
este caso solamente tiene las fechas del 2004 pero


facilmente y sin mucho
gasto de disco se pueden llenar los proximos 25 anos.
Contruyo la consulta por partes y en vistas para que


se entienda:
=>CREATE VIEW FechasConflicto
AS
SELECT FechasHlp.Fecha, COUNT(*) NumConflictos
FROM RangosFechas
JOIN FechasHlp
ON FechasHlp.Fecha BETWEEN RangosFechas.F_Inicio AND


RangosFechas.F_Fin
GROUP BY FechasHlp.Fecha
HAVING COUNT(*) > 1
=> La anterior consulta me dice para un dia especifico


si hay conflictos y
de haberlos cuantos son (minimo 2), basicamente por medio


del JOIN cuenta la
cantidad de filas en una fecha determinada. El


unico "truco" aqui es el uso
del BETWEEN en el JOIN, la mayoria de los programadores


solo usan = en el
JOIN.
=>CREATE VIEW InicioBloquesConflicto
AS
SELECT F1.Fecha AS FechaInicioConflicto
, F1.NumConflictos
FROM FechasConflicto AS F1
LEFT JOIN FechasConflicto AS F2
ON F1.FechaÚTEADD(day,-1,F2.Fecha)
AND F1.NumConflictosò.NumConflictos
WHERE F2.Fecha IS NULL
=> La anterior consulta me indica cuando empieza


un "Bloque de Conflicto"
esto es cuando la fecha anterior a esta o no tiene


conflicto o tiene un
conflicto con un numero diferente de recursos. Usa un


LEFT JOIN/WHERE IS
NULL para obtenter este resultado y la hace con un JOIN a


la misma Tabla por
lo que usa los nombres F1 y F2 para la Vista de


FechasConflicto.
Para obtener el resultado final:
=>SELECT InicioBloquesConflicto.NumConflictos
,


InicioBloquesConflicto.FechaInicioConflicto
, MAX(FC.Fecha) AS FechaFinalConflicto
FROM InicioBloquesConflicto
JOIN FechasConflicto AS FC
ON InicioBloquesConflicto.FechaInicioConflicto<ü.Fecha
AND


InicioBloquesConflicto.NumConflictosü.NumConflictos
AND
DATEDIFF


(day,InicioBloquesConflicto.FechaInicioConflicto,FC.Fecha)
+1> (SELECT COUNT(*)
FROM FechasConflicto
WHERE FechasConflicto.Fecha BETWEEN
InicioBloquesConflicto.FechaInicioConflicto
AND FC.Fecha
AND
FechasConflicto.NumConflictos=InicioBloquesConflicto.NumCo


nflictos)
GROUP BY InicioBloquesConflicto.NumConflictos
,


InicioBloquesConflicto.FechaInicioConflicto
=> Esta consulta es por cierto la mas complicada. La


intencion es buscar la
ultima Fecha de este bloque de conflictos, si obtiene con


un complicado JOIN
que incluye una SubConsulta (que son pesimas para el


desempeno). Es posible
que se puede simplificar haciendo otro JOIN y sacando el


COUNT(*), pero
asumo que ha esta altura del posteo nadie esta leyendo y


no voy a tener que
soportar criticas por el uso de SubConsultas :D
En cuanto al desempeno, en cantidades de datos


grandes es posible que
sea muy malo, la otra alternativa que se me ocurrio debe


ser mucho mas
rapida pero es MUCHO mas complicada.
Espero te sirva, yo disfrute mucho construyendola.
Saludos,

Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.

SRenau escribio:
Hola,

El problema es el siguiente, tengo una tabla con 3




campos
id, fecha_inicio, fecha_fin.

Desearia obtener las fechas para las cuales
hay "solapamiento" de dias y me cuente el numero de
registros que intervienen.

Ejemplo:

id f_inicio f_fin
1 01/07/2004 09/07/2004
2 06/07/2004 15/07/2004
3 18/07/2004 22/07/2004
4 01/08/2004 09/08/2004
5 04/08/2004 05/08/2004
6 05/08/2004 19/08/2004
7 11/09/2004 09/09/2004

Resultado

count f_inicio f_fin
2 06/07/2004 09/07/2004
3 05/08/2004 05/08/2004

Es dificil de explicar asi que si hay dudas preguntar.

Gracias.




.

Respuesta Responder a este mensaje
#7 Javier Loria
05/08/2004 - 03:58 | Informe spam
Hola:
Bueno, espero te sirva de algo.
En todo caso no entendi lo de los 100 millones de consultas para las
posibilidades, si puedes elaborar mas con gusto ayudo.
La otra alternativa (la que no expuse) es un poco mas compleja, pero es
probable que sea mas rapida. No la termine de elaborar totalmente, pero en
principio es mas "logica" esto es sin tabla de fechas, hace comparaciones
haciendo un "self join" o sea un join en ella misma, para encontrar los
conflictos, basados en los rangos de las fechas.
Una vez encontrados los conflictos, busca los conflictos entre los
conflictos para contar cuantos recursos se requieren.
Saludos,

Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.

SRenau escribio:
Hola de nuevo, y de nuevo gracias por el interes te has
pegado una buena currada.

Tengoq ue adentrar más, pero yo ya tantee esta posibilidad
en su dia y la complagidad de las tablas que "realmente"
necesito emplear me supondrian unos 100 millones de
consultas para testear todas las posibilidades para cada
dia.

Esto supongo que no sera muy practico, pero le voy ha dar
unas cuantas vueltas a tu "exposicion" a ver si me orienta
en un mejor camino.


Hola:
El problema es bien complejo y tiene mas implicaciones de Logica
que de SQL.
Antes de empezar, me parece hay dos errores.
a) La fila 7, la columna f_fin no debe ser 09/09/2004 ya que
terminaria antes de empezar, asi que asumo que es un error. Asumo
que la fecha seria 19/09/2004
b) El resultado de los conflictos no esta completo, ya que el dia
04/08/2004, hay conflicto entre la fila 4 y la fila 5.
Adicionalmente del dia 06/08/2004 al dia 09/08/2004 entre la fila 4
y 6. Entonces el Resultado de los conflictos deberia ser asi:
count f_inicio f_fin
-
2 06/07/2004 09/07/2004
2 04/08/2004 04/08/2004
3 05/08/2004 05/08/2004
2 06/08/2004 09/08/2004
=>> Si esto es correcto, entonces hay varias alternativas para encontrar
este conjunto de resultados. Estuve analizando 2 caminos, el mas
"sencillo" es de ayudarse de una Tabla de Fechas.
Basados en el siguiente Esquema:
=>> SET NOCOUNT ON
GO
CREATE TABLE RangosFechas(
RangoId INT NOT NULL
PRIMARY KEY
, F_Inicio SMALLDATETIME NOT NULL
CHECK(DATEPART(Hour, F_Inicio)=0
AND DATEPART(Minute, F_Inicio)=0)
, F_Fin SMALLDATETIME NOT NULL
CHECK(DATEPART(Hour, F_Fin)=0
AND DATEPART(Minute, F_Fin)=0)
, CONSTRAINT CH_RangosFechasInicioMenorFin
CHECK(F_Inicio<F_Fin)
)

INSERT RangosFechas(RangoId, F_Inicio, F_Fin)
SELECT 1, '2004/07/01','2004/07/09' UNION ALL
SELECT 2, '2004/07/06','2004/07/15' UNION ALL
SELECT 3, '2004/07/18','2004/07/22' UNION ALL
SELECT 4, '2004/08/01','2004/08/09' UNION ALL
SELECT 5, '2004/08/04','2004/08/05' UNION ALL
SELECT 6, '2004/08/05','2004/08/19' UNION ALL
SELECT 7, '2004/09/11','2004/09/19'

CREATE TABLE FechasHlp(
Fecha SMALLDATETIME
NOT NULL PRIMARY KEY
CHECK(DATEPART(Hour, Fecha)=0
AND DATEPART(Minute, Fecha)=0)
)
GO
DECLARE @Fecha SMALLDATETIME
SET @Fecha='2004/01/01'

WHILE @Fecha<'2005/01/01'
BEGIN
INSERT FechasHlp
VALUES (@Fecha)
SET @FechaÚTEADD(day,1,@Fecha)
END
=>> La tabla de FechasHlp es muy util para hacer este tipo de
consultas, en este caso solamente tiene las fechas del 2004 pero
facilmente y sin mucho gasto de disco se pueden llenar los proximos
25 anos. Contruyo la consulta por partes y en vistas para que se
entienda: =>> CREATE VIEW FechasConflicto
AS
SELECT FechasHlp.Fecha, COUNT(*) NumConflictos
FROM RangosFechas
JOIN FechasHlp
ON FechasHlp.Fecha BETWEEN RangosFechas.F_Inicio AND
RangosFechas.F_Fin GROUP BY FechasHlp.Fecha
HAVING COUNT(*) > 1
=>> La anterior consulta me dice para un dia especifico si hay
conflictos y de haberlos cuantos son (minimo 2), basicamente por
medio del JOIN cuenta la cantidad de filas en una fecha determinada.
El


unico "truco" aqui es el uso
del BETWEEN en el JOIN, la mayoria de los programadores solo usan >> en el JOIN.
=>> CREATE VIEW InicioBloquesConflicto
AS
SELECT F1.Fecha AS FechaInicioConflicto
, F1.NumConflictos
FROM FechasConflicto AS F1
LEFT JOIN FechasConflicto AS F2
ON F1.FechaÚTEADD(day,-1,F2.Fecha)
AND F1.NumConflictosò.NumConflictos
WHERE F2.Fecha IS NULL
=>> La anterior consulta me indica cuando empieza


un "Bloque de Conflicto"
esto es cuando la fecha anterior a esta o no tiene conflicto o tiene
un conflicto con un numero diferente de recursos. Usa un LEFT
JOIN/WHERE IS NULL para obtenter este resultado y la hace con un
JOIN a la misma Tabla por lo que usa los nombres F1 y F2 para la
Vista de FechasConflicto. Para obtener el resultado final:
=>> SELECT InicioBloquesConflicto.NumConflictos
, InicioBloquesConflicto.FechaInicioConflicto
, MAX(FC.Fecha) AS FechaFinalConflicto
FROM InicioBloquesConflicto
JOIN FechasConflicto AS FC
ON InicioBloquesConflicto.FechaInicioConflicto<ü.Fecha
AND InicioBloquesConflicto.NumConflictosü.NumConflictos
AND
DATEDIFF


(day,InicioBloquesConflicto.FechaInicioConflicto,FC.Fecha)
+1>> (SELECT COUNT(*)
FROM FechasConflicto
WHERE FechasConflicto.Fecha BETWEEN
InicioBloquesConflicto.FechaInicioConflicto
AND FC.Fecha
AND
FechasConflicto.NumConflictos=InicioBloquesConflicto.NumCo nflictos)
GROUP BY InicioBloquesConflicto.NumConflictos
, InicioBloquesConflicto.FechaInicioConflicto
=>> Esta consulta es por cierto la mas complicada. La intencion es
buscar la ultima Fecha de este bloque de conflictos, si obtiene con
un complicado JOIN que incluye una SubConsulta (que son pesimas para
el desempeno). Es posible que se puede simplificar haciendo otro
JOIN y sacando el COUNT(*), pero asumo que ha esta altura del posteo
nadie esta leyendo y no voy a tener que soportar criticas por el uso
de SubConsultas :D En cuanto al desempeno, en cantidades de datos
grandes es posible que sea muy malo, la otra alternativa que se me
ocurrio debe ser mucho mas rapida pero es MUCHO mas complicada.
Espero te sirva, yo disfrute mucho construyendola.
Saludos,

Javier Loria
Costa Rica
Se aprecia la inclusion de DDL (CREATE, INSERTS, etc.)
que pueda ser copiado y pegado al Query Analizer.
La version de SQL y Service Pack tambien ayuda.

SRenau escribio:
Hola,

El problema es el siguiente, tengo una tabla con 3 campos
id, fecha_inicio, fecha_fin.

Desearia obtener las fechas para las cuales
hay "solapamiento" de dias y me cuente el numero de
registros que intervienen.

Ejemplo:

id f_inicio f_fin
1 01/07/2004 09/07/2004
2 06/07/2004 15/07/2004
3 18/07/2004 22/07/2004
4 01/08/2004 09/08/2004
5 04/08/2004 05/08/2004
6 05/08/2004 19/08/2004
7 11/09/2004 09/09/2004

Resultado

count f_inicio f_fin
2 06/07/2004 09/07/2004
3 05/08/2004 05/08/2004

Es dificil de explicar asi que si hay dudas preguntar.

Gracias.




.
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida