Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách thực hiện tính tổng cuộn, mỗi hàng cần bao gồm tổng của các hàng trước đó

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_idprev_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.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Có thể sử dụng log4jdbc với khởi động mùa xuân không?

  2. Giải thích về MySqlBulkLoader

  3. MySQL - Chọn để truy xuất ngày giờ cuối cùng

  4. Làm cách nào để chỉ gửi sự kiện nhấp chuột (div), khi sử dụng hàm jquery live?

  5. Nhận kết nối PHP PDO từ mysql_connect ()?