Trong Bảng gốc
(truy vấn con bên trong FROM
), chúng tôi sắp xếp dữ liệu của mình sao cho tất cả các hàng có cùng user_id
các giá trị kết hợp với nhau, với việc sắp xếp thêm giữa chúng dựa trên game_detail
theo thứ tự giảm dần.
Bây giờ, chúng tôi sử dụng tập kết quả này và sử dụng CASE..WHEN
có điều kiện biểu thức để đánh giá việc đánh số hàng. Nó sẽ giống như một kỹ thuật Looping (mà chúng tôi sử dụng trong mã ứng dụng, ví dụ:PHP). Chúng tôi sẽ lưu trữ các giá trị của hàng trước đó trong các biến do Người dùng xác định, sau đó kiểm tra (các) giá trị của hàng hiện tại so với hàng trước đó. Cuối cùng, chúng tôi sẽ chỉ định số hàng cho phù hợp.
Chỉnh sửa: Dựa trên MySQL tài liệu và quan sát của @Gordon Linoff:
Thứ tự đánh giá cho các biểu thức liên quan đến biến người dùng được xác định. Ví dụ:không có gì đảm bảo rằng SELECT @a, @a: [email protected] + 1 đánh giá @a trước và sau đó thực hiện nhiệm vụ.
Chúng tôi sẽ cần đánh giá số hàng và chỉ định user_id
giá trị thành @u
biến trong cùng một biểu thức.
SET @r := 0, @u := 0;
SELECT
@r := CASE WHEN @u = dt.user_id
THEN @r + 1
WHEN @u := dt.user_id /* Notice := instead of = */
THEN 1
END AS user_game_rank,
dt.user_id,
dt.game_detail,
dt.game_id
FROM
( SELECT user_id, game_id, game_detail
FROM game_logs
ORDER BY user_id, game_detail DESC
) AS dt
Kết quả
| user_game_rank | user_id | game_detail | game_id |
| -------------- | ------- | ----------- | ------- |
| 1 | 6 | 260 | 11 |
| 2 | 6 | 100 | 10 |
| 1 | 7 | 1200 | 10 |
| 2 | 7 | 500 | 11 |
| 3 | 7 | 260 | 12 |
| 4 | 7 | 50 | 13 |
Một lưu ý thú vị từ MySQL Documents , mà tôi đã khám phá gần đây:
Các bản phát hành trước của MySQL cho phép gán một giá trị cho biến auser trong các câu lệnh không phải SET. Chức năng này được hỗ trợ trong MySQL 8.0 để tương thích ngược nhưng có thể bị hủy bỏ trong bản phát hành MySQL trong tương lai.
Ngoài ra, cảm ơn một thành viên SO khác, đã xem blog này của MySQL Team: https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/
Nhận xét chung là sử dụng ORDER BY
với đánh giá của các biến người dùng trong cùng một khối truy vấn, không đảm bảo rằng các giá trị sẽ luôn đúng. Như, trình tối ưu hóa MySQL có thể vào đúng vị trí và thay đổi giả định của chúng tôi thứ tự đánh giá.
Cách tốt nhất cho vấn đề này là nâng cấp lên MySQL 8+ và sử dụng Row_Number()
chức năng:
Giản đồ (MySQL v8.0)
SELECT user_id,
game_id,
game_detail,
ROW_NUMBER() OVER (PARTITION BY user_id
ORDER BY game_detail DESC) AS user_game_rank
FROM game_logs
ORDER BY user_id, user_game_rank;
Kết quả
| user_id | game_id | game_detail | user_game_rank |
| ------- | ------- | ----------- | -------------- |
| 6 | 11 | 260 | 1 |
| 6 | 10 | 100 | 2 |
| 7 | 10 | 1200 | 1 |
| 7 | 11 | 500 | 2 |
| 7 | 12 | 260 | 3 |
| 7 | 13 | 50 | 4 |