MySQL 5.7/8.0 前無內建 ROW_NUMBER(),需用戶變量模擬為查詢結果添加行號。本文提供標準寫法、分頁定位應用、臨時表替代方案對比,並說明 MySQL 8.0 原生視窗函數的遷移路徑。
-- 初始化計數器
SET @rownum := 0;
-- 查詢並生成行號
SELECT
(@rownum := @rownum + 1) AS row_num,
id, name, created_at
FROM articles
ORDER BY created_at DESC;
關鍵點:
@rownum 是用戶會話變量,連接級別有效:= 是賦值運算符(區別於 = 比較運算符)需求:查詢某文章在「按時間倒序」中的排名
SET @rownum := 0;
SELECT * FROM (
SELECT
(@rownum := @rownum + 1) AS row_num,
id, title, created_at
FROM articles
ORDER BY created_at DESC
) AS ranked
WHERE id = 12345; -- 目標文章 ID
結果中 row_num 即為該文章的排名位置。
SELECT
ROW_NUMBER() OVER (ORDER BY created_at DESC) AS row_num,
id, name, created_at
FROM articles;
優勢:標準 SQL、無會話變量副作用、優化器支援並行執行、可嵌套使用。
CREATE TEMPORARY TABLE tmp_ranked (
row_num INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
id INT, name VARCHAR(100), created_at DATETIME
) ENGINE=Memory;
INSERT INTO tmp_ranked (id, name, created_at)
SELECT id, name, created_at FROM articles ORDER BY created_at DESC;
SELECT * FROM tmp_ranked WHERE id = 12345;
| 方案 | 優點 | 缺點 | 適用版本 |
|---|---|---|---|
| 用戶變量 | 無建表開銷、單語句 | 依賴執行順序、8.0 優化器可能破壞、主從複製不安全 | 5.7/8.0(兼容) |
| 臨時表 AUTO_INCREMENT | 語義明確、可複用、主從安全(ROW格式) | 建表/寫入開銷、Memory 引擎大小限制、需顯式清理 | 全版本 |
| ROW_NUMBER() | 標準、高效、無副作用 | 需 8.0+ | 8.0+ 首選 |
用戶變量在 STATEMENT 格式 Binlog 下不安全(主從結果不一致)。解決:
binlog_format = ROW(推薦)SET SESSION binlog_format = 'ROW'ROW_NUMBER() OVER ()binlog_format=ROW 並驗證主從一致性