Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL consolidando linhas da tabela com períodos de data sobrepostos


Uma maneira de fazer isso é pelo uso de subconsultas correlacionadas:
SELECT DISTINCT
       (SELECT MIN(opens)
       FROM mytable AS t2
       WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS start,
       (SELECT MAX(closes)
       FROM mytable AS t2
       WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS end       
FROM mytable AS t1
ORDER BY opens

O WHERE predicados das subconsultas correlacionadas:

t2.opens <= t1.closes AND t2.closes >= t1.opens

retorna todos os registros sobrepostos relacionados ao registro atual. Realizando a agregação de um desses registros podemos encontrar as datas de início/fim de cada intervalo:a data de início do intervalo é a mínima opens data entre todos os registros sobrepostos, enquanto a data final é o máximo de closes encontro.

Demonstração aqui

EDITAR:

A solução acima não funcionará com um conjunto de intervalos como o seguinte:
1. |-----------|
2. |----|
3.           |-----|

Nº do registro 2, quando processado, produzirá um intervalo de início/fim defeituoso.

Aqui está uma solução usando variáveis:
SELECT MIN(start) AS start, MAX(end) AS end
FROM (
  SELECT @grp := IF(@start = '1900-01-01' OR 
                   (opens <= @end AND closes >= @start), @grp, @grp+1) AS grp,        
         @start := IF(@start = '1900-01-01', opens, 
                      IF(opens <= @end AND closes >= @start, 
                         IF (@start < opens, @start, opens), opens)) AS start,
         @end := IF(@end = '1900-01-01', closes, 
                    IF (opens <= @end AND closes >= @start, 
                      IF (@end > closes, @end, closes), closes)) AS end                 
  FROM mytable
  CROSS JOIN (SELECT @grp := 1, @start := '1900-01-01', @end := '1900-01-01') AS vars
  ORDER BY opens, DATEDIFF(closes, opens) DESC) AS t
GROUP BY grp

A idéia é começar do opens/closes mais à esquerda intervalo. Variáveis ​​@start , @end são usados ​​para propagar o intervalo consolidado de expansão incremental (à medida que novas linhas sobrepostas estão sendo processadas) na cadeia de intervalos. Quando um intervalo não sobreposto é encontrado, [@start - @end] é inicializado para corresponder a este novo intervalo e grp é incrementado em um.

Demonstração aqui