Một cách để làm điều đó là sử dụng các truy vấn con tương quan:
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
các vị từ của các truy vấn con tương quan:
t2.opens <= t1.closes AND t2.closes >= t1.opens
trả lại tất cả các bản ghi chồng chéo liên quan đến bản ghi hiện tại. Thực hiện tổng hợp một trong những bản ghi này, chúng ta có thể tìm thấy ngày bắt đầu / ngày kết thúc của mỗi khoảng thời gian:ngày bắt đầu của khoảng thời gian là ngày opens
tối thiểu ngày giữa tất cả các bản ghi chồng chéo, trong khi ngày kết thúc là ngày closes
tối đa ngày tháng.
CHỈNH SỬA:
Giải pháp trên sẽ không hoạt động với một tập hợp các khoảng thời gian như sau:
1. |-----------|
2. |----|
3. |-----|
Ghi không. 2, khi được xử lý, sẽ tạo ra khoảng thời gian bắt đầu / kết thúc thiếu sót.
Đây là một giải pháp sử dụng các biến:
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
Ý tưởng là bắt đầu từ opens/closes
ngoài cùng bên trái khoảng thời gian. Các biến @start
, @end
được sử dụng để truyền khoảng thời gian hợp nhất mở rộng dần dần (khi các hàng chồng chéo mới đang được xử lý) xuống chuỗi khoảng thời gian. Sau khi gặp phải khoảng thời gian không trùng lặp, [@start - @end]
được khởi tạo để khớp với khoảng thời gian mới này và grp
được tăng lên một.