Đây là một cách tiếp cận.
Bắt đầu bằng cách sắp xếp các hàng trạng thái theo dấu thời gian (chế độ xem nội tuyến được đặt bí danh là s
). Sau đó, sử dụng các biến người dùng MySQL để giữ các giá trị từ các hàng trước khi bạn xử lý qua từng hàng.
Những gì chúng tôi thực sự đang tìm kiếm là trạng thái 'tăng' ngay sau một chuỗi trạng thái 'xuống'. Và khi chúng tôi tìm thấy hàng có trạng thái 'tăng', điều chúng tôi thực sự cần là dấu thời gian sớm nhất từ chuỗi trạng thái 'giảm' trước đó.
Vì vậy, một cái gì đó như thế này sẽ hoạt động:
SELECT d.start_down
, d.ended_down
FROM (SELECT @i := @i + 1 AS i
, @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
, @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
, @status := s.status
FROM (SELECT t.time
, t.status
FROM mydata t
WHERE t.status IN ('up','down')
ORDER BY t.time ASC, t.status ASC
) s
JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i
) d
WHERE d.start_down IS NOT NULL
AND d.ended_down IS NOT NULL
Điều này phù hợp với tập dữ liệu cụ thể mà bạn hiển thị.
Điều này không xử lý được (những gì nó không trả về) là một khoảng thời gian 'xuống' chưa kết thúc, tức là một chuỗi trạng thái 'xuống' mà không có trạng thái 'lên' theo sau.
Để tránh thao tác sắp xếp tệp để trả về các hàng theo thứ tự, bạn sẽ muốn có một chỉ mục bao gồm trên (time,status)
. Truy vấn này sẽ tạo một bảng (MyISAM) tạm thời để hiện thực hóa chế độ xem nội tuyến có bí danh là d
.
LƯU Ý: Để hiểu truy vấn này đang làm gì, hãy bóc truy vấn ngoài cùng và chỉ chạy truy vấn cho chế độ xem nội tuyến có bí danh là d
(bạn có thể thêm s.time
vào danh sách đã chọn.)
Truy vấn này nhận được mọi hàng có trạng thái "lên" hoặc "xuống". "Thủ thuật" là nó chỉ định cả thời gian "bắt đầu" và "kết thúc" (đánh dấu khoảng thời gian giảm) chỉ trên các hàng kết thúc khoảng thời gian 'giảm'. (Tức là hàng đầu tiên có trạng thái 'tăng' sau các hàng có trạng thái 'xuống'.) Đây là nơi công việc thực sự được thực hiện, truy vấn ngoài cùng chỉ lọc ra tất cả các hàng "bổ sung" trong tập kết quả này (mà chúng tôi không cần.)
SELECT @i := @i + 1 AS i
, @start := IF(s.status = 'down' AND (@status = 'up' OR @i = 1), s.time, @start) AS start_down
, @ended := IF(s.status = 'up' AND @status = 'down', s.time, NULL) AS ended_down
, @status := s.status
, s.time
FROM (SELECT t.time
, t.status
FROM mydata t
WHERE t.status IN ('up','down')
ORDER BY t.time ASC, t.status ASC
) s
JOIN (SELECT @i := 0, @status := 'up', @ended := NULL, @start := NULL) i
Mục đích của chế độ xem nội tuyến được đặt bí danh là s
là lấy các hàng được sắp xếp theo giá trị dấu thời gian, vì vậy chúng tôi có thể xử lý chúng theo trình tự. Chế độ xem nội tuyến có bí danh là i
chỉ ở đó để chúng tôi có thể khởi tạo một số biến người dùng khi bắt đầu truy vấn.
Nếu chúng tôi đang chạy trên Oracle hoặc SQL Server, chúng tôi có thể sử dụng "các hàm phân tích" hoặc "các hàm xếp hạng" (như chúng được đặt tên tương ứng.) MySQL không cung cấp bất kỳ thứ gì như vậy, vì vậy chúng tôi phải "tự mình thực hiện ".