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
 108
Author: fthiella, 2008-09-27

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
 394
Author: Lasse Vågsæther Karlsen,
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.

 8
Author: Paul Dixon,
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).

 4
Author: David Aldridge,
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; -)

 0
Author: onedaywhen,
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 ;
 0
Author: jonavon,
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
 0
Author: Rama Subba Reddy M,
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];
 0
Author: RickyS,
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;
 0
Author: Paul Williamson,
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)
 0
Author: Florian HENRY - ATM Consulting,
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) )
 -2
Author: Gio,
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