por - sql server comparar fechas mayor
ComparaciĆ³n de los intervalos de fechas (10)
Creé una función para tratar este problema en MySQL. Simplemente convierta las fechas en segundos antes de usar.
DELIMITER ;;
CREATE FUNCTION overlap_interval(x INT,y INT,a INT,b INT)
RETURNS INTEGER DETERMINISTIC
BEGIN
DECLARE
overlap_amount INTEGER;
IF (((x <= a) AND (a < y)) OR ((x < b) AND (b <= y)) OR (a < x AND y < b)) THEN
IF (x < a) THEN
IF (y < b) THEN
SET overlap_amount = y - a;
ELSE
SET overlap_amount = b - a;
END IF;
ELSE
IF (y < b) THEN
SET overlap_amount = y - x;
ELSE
SET overlap_amount = b - x;
END IF;
END IF;
ELSE
SET overlap_amount = 0;
END IF;
RETURN overlap_amount;
END ;;
DELIMITER ;
En MySQL, si tengo una lista de rangos de fechas (range-start y range-end). p.ej
10/06/1983 to 14/06/1983
15/07/1983 to 16/07/1983
18/07/1983 to 18/07/1983
Y quiero verificar si otro rango de fechas contiene CUALQUIERA de los rangos que ya están en la lista, ¿cómo lo haría?
p.ej
06/06/1983 to 18/06/1983 = IN LIST
10/06/1983 to 11/06/1983 = IN LIST
14/07/1983 to 14/07/1983 = NOT IN LIST
En tus resultados esperados dices
06/06/1983 a 18/06/1983 = EN LA LISTA
Sin embargo, este período no contiene ni está contenido en ninguno de los períodos en su tabla (¡no en la lista!) De períodos. Sin embargo, se superpone el período del 10/06/1983 al 14/06/1983.
Puede encontrar el libro Snodgrass ( http://www.cs.arizona.edu/people/rts/tdbbook.pdf ) útil: es anterior a mysql pero el concepto de tiempo no ha cambiado ;-)
Este es un problema clásico, y en realidad es más fácil si revierte la lógica.
Dejame darte un ejemplo.
Voy a publicar un período de tiempo aquí, y todas las diferentes variaciones de otros períodos que se superponen de alguna manera.
|-------------------| compare to this one
|---------| contained within
|----------| contained within, equal start
|-----------| contained within, equal end
|-------------------| contained within, equal start+end
|------------| not fully contained, overlaps start
|---------------| not fully contained, overlaps end
|-------------------------| overlaps start, bigger
|-----------------------| overlaps end, bigger
|------------------------------| overlaps entire period
por otro lado, permítanme publicar todos los que no se superponen:
|-------------------| compare to this one
|---| ends before
|---| starts after
Entonces, si simplemente reduce la comparación a:
starts after end
ends before start
luego encontrarás todos aquellos que no se superponen, y luego encontrarás todos los períodos que no coinciden.
Para su ejemplo final NOT IN LIST, puede ver que coincide con esas dos reglas.
Tendrá que decidir si los siguientes períodos están dentro o fuera de sus rangos:
|-------------|
|-------| equal end with start of comparison period
|-----| equal start with end of comparison period
Si su tabla tiene columnas llamadas range_end y range_start, aquí hay algunos SQL simples para recuperar todas las filas coincidentes:
SELECT *
FROM periods
WHERE NOT (range_start > @check_period_end
OR range_end < @check_period_start)
Tenga en cuenta el NO allí. Como las dos reglas simples encuentran todas las filas que no coinciden , un simple NOT lo invertirá para decir: si no es una de las filas que no coinciden, tiene que ser una de las que coincidan .
Aplicando la lógica de reversión simple aquí para deshacerte del NOT y terminarás con:
SELECT *
FROM periods
WHERE range_start <= @check_period_end
AND range_end >= @check_period_start
Mire en el siguiente ejemplo. Te será útil.
SELECT DISTINCT RelatedTo,CAST(NotificationContent as nvarchar(max)) as NotificationContent,
ID,
Url,
NotificationPrefix,
NotificationDate
FROM NotificationMaster as nfm
inner join NotificationSettingsSubscriptionLog as nfl on nfm.NotificationDate between nfl.LastSubscribedDate and isnull(nfl.LastUnSubscribedDate,GETDATE())
where ID not in(SELECT NotificationID from removednotificationsmaster where Userid=@userid) and nfl.UserId = @userid and nfl.RelatedSettingColumn = RelatedTo
Otro método al usar BETWEEN sentencia sql
Períodos incluidos:
SELECT *
FROM periods
WHERE @check_period_start BETWEEN range_start AND range_end
AND @check_period_end BETWEEN range_start AND range_end
Periodos excluidos:
SELECT *
FROM periods
WHERE (@check_period_start NOT BETWEEN range_start AND range_end
OR @check_period_end NOT BETWEEN range_start AND range_end)
Pruebe esto en MS SQL
WITH date_range (calc_date) AS (
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, [ending date]) - DATEDIFF(DAY, [start date], [ending date]), 0)
UNION ALL SELECT DATEADD(DAY, 1, calc_date)
FROM date_range
WHERE DATEADD(DAY, 1, calc_date) <= [ending date])
SELECT P.[fieldstartdate], P.[fieldenddate]
FROM date_range R JOIN [yourBaseTable] P on Convert(date, R.calc_date) BETWEEN convert(date, P.[fieldstartdate]) and convert(date, P.[fieldenddate])
GROUP BY P.[fieldstartdate], P.[fieldenddate];
Si su RDBMS es compatible con la función OVERLAP (), esto se convierte en algo trivial, sin necesidad de soluciones propias. (En Oracle, aparentemente funciona pero no está documentado).
Tomando su rango de ejemplo del 06/06/1983 al 18/06/1983 y suponiendo que tiene columnas llamadas inicio y fin para sus rangos, puede usar una cláusula como esta
where (''1983-06-06'' <= end) and (''1983-06-18'' >= start)
es decir, verifique que el inicio de su rango de prueba esté antes del final del rango de la base de datos, y que el final de su rango de prueba esté después o al comienzo del rango de la base de datos.
CREATE FUNCTION overlap_date(s DATE, e DATE, a DATE, b DATE)
RETURNS BOOLEAN DETERMINISTIC
RETURN s BETWEEN a AND b or e BETWEEN a and b or a BETWEEN s and e;
SELECT *
FROM tabla a
WHERE ( @Fini <= a.dFechaFin AND @Ffin >= a.dFechaIni )
AND ( (@Fini >= a.dFechaIni AND @Ffin <= a.dFechaFin) OR (@Fini >= a.dFechaIni AND @Ffin >= a.dFechaFin) OR (a.dFechaIni>=@Fini AND a.dFechaFin <=@Ffin) OR
(a.dFechaIni>=@Fini AND a.dFechaFin >=@Ffin) )