sql >> Databasteknik >  >> RDS >> Mysql

MySQL konsoliderar tabellrader med överlappande datumintervall

Ett sätt att göra det är genom att använda korrelerade underfrågor:

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

WHERE predikat för de korrelerade underfrågorna:

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

returnera alla överlappande poster relaterade till den aktuella posten. Genom att aggregera dessa poster kan vi hitta start-/slutdatum för varje intervall:startdatumet för intervallet är det minsta opens datum mellan alla överlappande poster, medan slutdatumet är det maximala closes datum.

Demo här

EDIT:

Ovanstående lösning fungerar inte med en uppsättning intervall som följande:

1. |-----------|
2. |----|
3.           |-----|

Rekordnr. 2, när den bearbetas, ger ett felaktigt start-/slutintervall.

Här är en lösning som använder variabler:

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

Tanken är att börja från opens/closes längst till vänster intervall. Variabler @start , @end används för att sprida det inkrementellt expanderande (eftersom nya överlappande rader bearbetas) konsoliderade intervall nedåt i intervallkedjan. När ett icke-överlappande intervall påträffas, [@start - @end] initieras för att matcha detta nya intervall och grp ökas med ett.

Demo här




  1. I klausul kontra OR-klausul prestationsmässigt

  2. Är det möjligt att optimera frågan med hjälp av EXISTS istället för IN-satsen med DISTINCT

  3. Infoga SQL Server-data i Salesforce.com

  4. ORA-00904:ogiltig identifierare