Tóm tắt
Trước MySQL 8.0 không có hàm window LAG(). Bài viết示范用 biến người dùng (@f, @s) và self-join để tính tỷ lệ giữa hàng hiện tại và hàng trước (lag 1).
Ví dụ dữ liệu
CREATE TABLE LagDemo (UserId INT, UserValue INT);
INSERT INTO LagDemo VALUES
(12,158), (18,756), (15,346), (87,646),
(27,334), (90,968), (84,378), (85,546);
Truy vấn mô phỏng LAG
SET @f := 0;
SET @s := 2;
SELECT l1.UserId, l1.UserValue,
l1.UserValue / l2.UserValue AS `LAG`
FROM (
SELECT IF(@f, @f := @f + 1, @f := 1) AS RowNumber, UserId, UserValue
FROM LagDemo
) AS l1
LEFT JOIN (
SELECT IF(@s, @s := @s + 1, @s := 1) AS RowNumber, UserId, UserValue
FROM LagDemo
) AS l2 ON l1.RowNumber = l2.RowNumber;
Kết quả
+--------+-----------+--------+
| UserId | UserValue | LAG |
+--------+-----------+--------+
| 12 | 158 | NULL |
| 18 | 756 | NULL |
| 15 | 346 | 2.1899 |
| 87 | 646 | 0.8545 |
| 27 | 334 | 0.9653 |
| 90 | 968 | 1.4985 |
| 84 | 378 | 1.1317 |
| 85 | 546 | 0.5640 |
+--------+-----------+--------+
Giải thích kỹ thuật
@fbắt đầu từ 0, tăng 1 mỗi hàng → đánh số thứ tự 1,2,3...@sbắt đầu từ 2, tăng 1 mỗi hàng → đánh số 2,3,4...- Join trên
RowNumberkhiến hàng 1 join với hàng 2, hàng 2 join với hàng 3... → tạo hiệu ứng LAG 1. - Hai hàng đầu tiên không có hàng trước → NULL.
Khuyên dùng MySQL 8.0+
SELECT UserId, UserValue,
UserValue / LAG(UserValue) OVER (ORDER BY UserId) AS LAG
FROM LagDemo;
Cách này chuẩn SQL, dễ đọc, hiệu năng tốt hơn, không phụ thuộc thứ tự vật lý.