Comparación de intervalos de fechas
En MySQL, Si tengo una lista de rangos de fechas (range-start y range-end). por ejemplo,
10/06/1983 to 14/06/1983
15/07/1983 to 16/07/1983
18/07/1983 to 18/07/1983
Y quiero comprobar si otro rango de fechas contiene CUALQUIERA de los rangos ya en la lista, ¿cómo lo haría?
Por ejemplo
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
10 answers
Este es un problema clásico, y en realidad es más fácil si se invierte la lógica.
Permítanme darles un ejemplo.
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 aquellos que no se superponen:
|-------------------| compare to this one
|---| ends before
|---| starts after
Así que si usted simple reducir la comparación a:
starts after end
ends before start
Entonces encontrarás todos los que no se superponen, y luego encontrarás todos los períodos no coincidentes.
Para su ejemplo final DE NO EN LA LISTA, 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 un SQL simple para recuperar todas las filas coincidentes:
SELECT *
FROM periods
WHERE NOT (range_start > @check_period_end
OR range_end < @check_period_start)
Note elNO allí. Dado que las dos reglas simples encuentra todas las filas no coincidentes, un simple NO invertirá es decir: si no es una de las filas que no coinciden, tiene que ser una de las filas que coinciden.
Aplicando una lógica de reversión simple aquí para deshacerse del NOT y terminarás con:
SELECT *
FROM periods
WHERE range_start <= @check_period_end
AND range_end >= @check_period_start
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-05 00:59:48
Tomando su rango de ejemplo de 06/06/1983 a 18/06/1983 y asumiendo que tiene columnas llamadas start y end para sus rangos, podría usar una cláusula como esta
where ('1983-06-06' <= end) and ('1983-06-18' >= start)
Es decir, compruebe que el inicio de su rango de prueba es antes del final del rango de la base de datos, y que el final de su rango de prueba es después o en el inicio del rango de la base de datos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 12:41:20
Si su RDBMS soporta la función OVERLAP() entonces esto se vuelve trivial no no hay necesidad de soluciones de cosecha propia. (En Oracle funciona aparentemente pero no está documentado).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-22 23:43:00
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 por ninguno de los períodos en su tabla (¡no enumere!) de períodos. Sin embargo, se superpone al período comprendido entre el 10/06/1983 y el 14/06/1983.
Usted 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; -)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-29 13:47:03
He creado la función para tratar este problema en MySQL. Simplemente convierta las fechas a 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 ;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-03 03:24:04
Mira el siguiente ejemplo. Será útil para usted.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-19 05:52:27
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];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-07 08:21:16
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;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-29 08:05:46
Otro método usando ENTRE la instrucción 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
Períodos 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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-15 12:35:22
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) )
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-22 18:27:50