Bạn có thể sử dụng các biến người dùng MySQL để mô phỏng các hàm phân tích. (Ngoài ra còn có một số cách tiếp cận khác, chẳng hạn như sử dụng bán nối hoặc sử dụng truy vấn con có liên quan. Tôi cũng có thể cung cấp giải pháp cho những cách tiếp cận đó, nếu bạn cảm thấy chúng có thể phù hợp hơn.)
Để mô phỏng một hàm phân tích "tổng đang chạy", hãy thử một cái gì đó như sau:
SELECT t.user_id
, t.starttime
, t.order_number
, IF(t.order_number IS NOT NULL,
@tot_dur := 0,
@tot_dur := @tot_dur + t.visit_duration_seconds) AS tot_dur
FROM visit t
JOIN (SELECT @tot_dur := 0) d
ORDER BY t.user_id, t.start_time
"Mẹo" ở đây là sử dụng hàm IF để kiểm tra xem có hay không order_number
là null. Khi giá trị rỗng, chúng tôi thêm giá trị thời lượng vào biến, nếu không, chúng tôi đặt biến bằng không.
Chúng tôi sử dụng chế độ xem nội tuyến (bí danh là d
, để đảm bảo rằng biến @tot_dur được khởi tạo bằng 0.
LƯU Ý:Hãy cẩn thận với việc sử dụng các biến người dùng MySQL như thế này. Trong câu lệnh SELECT như trên, việc gán các biến trong danh sách SELECT xảy ra sau ORDER BY, vì vậy chúng ta có thể nhận được hành vi xác định.
Truy vấn đó không xử lý "ngắt" trong user_id. Để có được điều đó, chúng ta sẽ cần giá trị của user_id từ hàng trước. Chúng tôi có thể bảo vệ điều đó trong một biến người dùng khác. Thứ tự của các hoạt động là xác định và chúng ta cần chú ý thực hiện tích lũy TRƯỚC KHI chúng ta ghi đè user_id từ hàng trước đó.
Chúng ta cần sắp xếp lại các cột để user_id xuất hiện sau tot_dur (hoặc bao gồm bản sao thứ hai của cột user_id)
SELECT t.user_id
, t.starttime
, t.order_number
, IF(t.order_number IS NULL,
@tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
@tot_dur := 0
) AS tot_dur
, @prev_user_id := t.user_id AS prev_user_id
FROM visit t
JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
ORDER BY t.user_id, t.start_time
Các giá trị được trả về trong user_id
và prev_user_id
các cột giống hệt nhau. Cột "bổ sung" đó có thể bị xóa hoặc các cột có thể được sắp xếp lại thứ tự bằng cách đưa truy vấn (dưới dạng chế độ xem nội tuyến) vào một truy vấn khác, mặc dù điều này đi kèm với chi phí hiệu suất:
SELECT v.user_id
, v.starttime
, v.order_number
, v.tot_dur
FROM (SELECT t.starttime
, t.order_number
, IF(t.order_number IS NULL,
@tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
@tot_dur := 0
) AS tot_dur
, @prev_user_id := t.user_id AS user_id
FROM visit t
JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
ORDER BY t.user_id, t.start_time
) v
Truy vấn đó chứng tỏ rằng MySQL có thể trả về tập kết quả được chỉ định. Nhưng để có hiệu suất tối ưu, chúng tôi chỉ muốn chạy truy vấn trong chế độ xem nội tuyến (bí danh là v
) và xử lý việc sắp xếp lại các cột (đặt cột user_id lên trước) ở phía máy khách, khi các hàng được truy xuất.
Hai cách tiếp cận phổ biến khác là sử dụng bán nối và sử dụng truy vấn con tương quan, mặc dù những cách tiếp cận này có thể tốn nhiều tài nguyên hơn khi xử lý các tập hợp lớn.