Mysql
根據兩個條件 SQL 獲取某行上方和下方(相鄰行)的行
假設我有一張這樣的桌子:
+---+-------+------+---------------------+ |id | level |score | timestamp | +---+-------+------+---------------------+ | 4 | 1 | 70 | 2021-01-14 21:50:38 | | 3 | 1 | 90 | 2021-01-12 15:38:0 | | 1 | 1 | 20 | 2021-01-14 13:10:12 | | 5 | 1 | 50 | 2021-01-13 12:32:11 | | 7 | 1 | 50 | 2021-01-14 17:15:20 | | 8 | 1 | 55 | 2021-01-14 09:20:00 | | 10| 2 | 99 | 2021-01-15 10:50:38 | | 2 | 1 | 45 | 2021-01-15 10:50:38 | +---+-------+------+---------------------+
我想要做的是在一個表中顯示其中的 5 行(在 html 中),中間有某一行(例如 id=5),並在其上方和下方有兩行(以正確的順序)。還有級別= 1。這就像一個計分板,但只顯示使用者的分數,上面兩個,下面兩個。所以因為分數可以相同,所以還需要使用時間戳列——所以如果兩個分數相等,那麼第一個獲得分數的人會顯示在另一個人的上方。
例如說使用者是 id=5,我想顯示
+---+-------+------+---------------------+ |id | level |score | timestamp | +---+-------+------+---------------------+ | 4 | 1 | 70 | 2021-01-14 21:50:38 | | 8 | 1 | 55 | 2021-01-14 09:20:00 | | 5 | 1 | 50 | 2021-01-13 12:32:11 | | 7 | 1 | 50 | 2021-01-14 17:15:20 | | 2 | 1 | 45 | 2021-01-15 10:50:38 | | 1 | 1 | 20 | 2021-01-14 13:10:12 | +---+-------+------+---------------------+
注意 id=7 低於 id=5
我想知道有人知道這樣做的方法嗎?
我在下面嘗試過,但它沒有輸出我需要的東西(它輸出的地方 level_id=2 和 id=5,其他行不按順序排列)
((SELECT b.* FROM table a JOIN table b ON b.score > a.score OR (b.score = a.score AND b.timestamp < a.timestamp) WHERE a.level_id = 1 AND a.id = 5 ORDER BY score ASC, timestamp DESC LIMIT 3) UNION ALL (SELECT b.* FROM table a JOIN table b ON b.score < a.score OR (b.score = a.score AND b.timestamp > a.timestamp) WHERE a.level_id = 1 AND a.id = 5 ORDER BY score DESC, timestamp ASC LIMIT 2)) order by score
如果更容易輸出表中的所有行,說哪裡 level = 1,所以它是一個滿分板.. 然後使用 PHP 獲取某一行和上下兩行我也想知道請 :) !(可能認為這可能會使 SQL 更簡單)?
id 5 和 LIMIT 的值必須預先計算並傳遞給查詢,因為 LIMIT 必須具有固定值,否則您必須使用準備好的語句
CREATE TABLE table1 (`id` int, `level` int, `score` int, `timestamp` varchar(19)) ; INSERT INTO table1 (`id`, `level`, `score`, `timestamp`) VALUES (4, 1, 70, '2021-01-14 21:50:38'), (3, 1, 90, '2021-01-12 15:38:0'), (1, 1, 20, '2021-01-14 13:10:12'), (5, 1, 50, '2021-01-13 12:32:11'), (7, 1, 50, '2021-01-14 17:15:20'), (8, 1, 55, '2021-01-14 09:20:00'), (10, 2, 99, '2021-01-15 10:50:38'), (2, 1, 45, '2021-01-15 10:50:38') ;
SELECT `id`, `level`, `score` FROM ((SELECT `id`, `level`, `score`, 1 orderby FROM table1 a WHERE level = 1 AND `score` > (SELECT `score` FROM table1 WHERE id = 5) ORDER BY `score` ASC LIMIT 2) UNION ALL (SELECT `id`, `level`, `score`, 2 orderby FROM table1 a WHERE id = 5) UNION ALL (SELECT `id`, `level`, `score`, 3 orderby FROM table1 a WHERE level = 1 AND `score` <= (SELECT `score` FROM table1 WHERE id = 5) AND id <> 5 ORDER BY `score` DESC LIMIT 3)) t1 ORDER BY orderby ASC , score DESC
編號 | 水平 | 分數 -: | ----: | ----: 4 | 1 | 70 8 | 1 | 55 5 | 1 | 50 7 | 1 | 50 2 | 1 | 45 1 | 1 | 20
db<>在這裡擺弄
SELECT z.id, z.level, z.score, z.`timestamp` FROM ( SELECT w.* , @num := @num+1 AS num -- just to get the 'num' for middle line: , IF( w.id = 5, @hit := @num, NULL ) AS unused FROM table AS w WHERE @num := 1 -- UDV initialization AND w.level = 1 ORDER BY w.score DESC , w.`timestamp` ASC ) AS z WHERE z.num BETWEEN @hit-2 AND @hit+2 -- how many rows above and below ORDER BY z.num ASC ;
Subselect 列舉按分數和時間戳排序的行,並將
@num
給定 ID 的值儲存在使用者定義的變數@hit
中。外部選擇僅過濾給定範圍內的行。Dbfiddle 對 UDV 的工作非常糟糕,因此您必須在真實數據庫上測試該程式碼。