簡體   English   中英

mySQL - 選擇前n行,按2列分組

[英]mySQL - select the top n rows, grouped by 2 columns

我已經找到了現有的問題,包括幾個字段的最新/最低單行,或單個字段上的最新n行,但不是兩個在一起

我需要構建2個查詢,使用此示例表(類似於此問題

CREATE TABLE lap_data (
     id            int(1)     NOT NULL,
     track_id      int(1)     NOT NULL,
     user_id       int(1)     NOT NULL,
     lap_time      time       NOT NULL,
     lap_status    tinyint(1) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

INSERT INTO `lap_data` (`id`, `track_id`, `user_id`, `lap_time`, `lap_status`) VALUES
(1, 1, 1, '04:18:23', 1),
(2, 2, 2, '01:09:54', 1),
(3, 2, 1, '01:05:30', 1),
(4, 1, 2, '04:17:02', 1),
(5, 3, 2, '01:13:10', 1),
(6, 4, 1, '01:36:59', 0),
(7, 3, 2, '01:18:10', 1),
(8, 2, 3, '01:06:42', 1),
(9, 1, 1, '04:16:12', 1),
(10, 1, 2, '04:18:12', 1),
(11, 2, 3, '01:03:20', 1),
(12, 2, 1, '01:08:13', 1),
(13, 2, 1, '01:09:44', 1),
(14, 3, 2, '01:14:10', 1),
(15, 3, 2, '01:17:20', 1),
(16, 4, 1, '01:36:23', 1),
(17, 2, 1, '01:11:34', 1);

查詢1:

  • 我想通過lap_time獲得前2個結果 - 每個用戶每個音軌
    • 所以如果給定的user_id有超過3個軌道的20條記錄......
      • 我期望該user_id有6個結果
      • 或者如果其中一首曲目只有一條記錄
    • 兩個不同軌道的相同單圈時間都應該顯示,而不是只出現一次
  • 我想在第1部分中使用WHERE user_id IN(..)
  • 按給定字段排序,即lap_time
  • 其中lap_status = 1

這是我在其他地方用來收集給定類型的兩個最新記錄的查詢,這個記錄最接近我認為我需要的,修改為這個例子..雖然未完成,但在另一個例子中,它只是收集每個user_id的2個最新行..在這里我需要它也考慮到track_id

 SELECT
 * 
 FROM (
     SELECT
     t.id,
     t.track_id,
     t.user_id,
     t.lap_time,
     t.lap_status,
     @row:=case WHEN @prev=user_id THEN @row ELSE 0 END +1 rn,
     @prev:=user_id
     FROM `lap_data` t
     CROSS JOIN (SELECT @row:=0, @prev:=null) c
     WHERE t.user_id IN (1,2)
     ORDER BY user_id, id DESC
 ) src
 WHERE rn <= 2
 ORDER BY lap_time DESC

查詢1所需結果: (WHERE user_id IN(1,2))

|  id  |  track_id  |  user_id  |  lap_time  |  lap_status  |
--------------------------------------------------------------
|   9  |         1  |        1  |  04:16:12  |           1  |
|   1  |         1  |        1  |  04:18:23  |           1  |
|   3  |         2  |        1  |  01:05:30  |           1  |
|  12  |         2  |        1  |  01:08:13  |           1  |
|  16  |         4  |        1  |  01:36:23  |           1  |
|   6  |         4  |        1  |  01:36:59  |           1  |
|   4  |         1  |        2  |  04:17:02  |           1  |
|  10  |         1  |        2  |  04:18:12  |           1  |
|   2  |         2  |        2  |  01:09:54  |           1  |
|   5  |         3  |        2  |  01:13:10  |           1  |
|  14  |         3  |        2  |  01:14:10  |           1  |

查詢2:

  • 對於單個用戶,我想獲得上述的反轉
    • 即結果的其余部分,不包括前兩個,僅針對特定的user_id

查詢2所需結果: (WHERE user_id ='1')

|  id  |  track_id  |  user_id  |  lap_time  |  lap_status  |
--------------------------------------------------------------
|  13  |         2  |        1  |  01:09:44  |           1  |
|  17  |         2  |        1  |  01:11:34  |           1  |

有什么建議么? 謝謝!

我之前回答的MYSQL版本:

SELECT 
lt.id,
lt.user_id,
lt.track_id,
lt.lap_status,
lt.lap_time 
FROM (
SELECT id,
    user_id,
    track_id,
    lap_status,
    lap_time,
    CASE WHEN track_id = @prevTrackId AND user_id = @prevUserId THEN @curRank := @curRank + 1 ELSE @curRank := 1 END Rank,
    @prevTrackId := track_id,
    @prevUserId := user_id
FROM lap_data, (SELECT @curRank := 0, @prevTrackId := 1, @prevUserId := 1) r
ORDER BY user_id,track_id,lap_time ASC
) lt 
WHERE Rank <= 2

該查詢產生一個重要的(並且很可能是錯誤的)假設 - 即先前用戶的最高track_id高於(或至少不同)后續用戶的最低track_id。

如果不是這種情況,那么您可能需要存儲另一個變量,或者將“prev”基於兩個值的串聯...

 SELECT x.id
      , x.track_id 
      , x.user_id 
      , x.lap_time 
      , x.lap_status 
   FROM 
      ( SELECT l.*
             , CASE WHEN @prev = track_id THEN @i:=@i+1 ELSE @i:=1 END rank
             , @prev:=track_id prev 
          FROM lap_data l
             , (SELECT @prev:=null,@i:=0) vars 
         WHERE user_id IN(1,2) 
         ORDER 
            BY user_id
             , track_id
             , lap_time
      ) x
  WHERE x.rank <=2
  ORDER 
     BY user_id
      , track_id
      , lap_time;
select id,track_id,user_id,lap_status,lap_time from (
select @rank:=if(@prev_cat=user_id,@rank+1,1) as rank,id,user_id,track_id,lap_status,lap_time,@prev_cat:=user_id
from lap_data,(select @rank:=0, @prev_cat:="")t
where user_id IN(1,2) order by track_id, user_id desc
  ) temp
  where temp.rank<=2

查詢1:

SELECT lt.id,lt.user_id,lt.track_id,lt.lap_status,lt.lap_time 
FROM (
    SELECT id,user_id,track_id,lap_status,lap_time,Rank() 
    over (Partition BY user_id,track_id
    ORDER BY lap_time ASC ) AS Rank
    FROM lap_data
    WHERE user_id IN (1,2)
) lt WHERE Rank <= 2

查詢2:只需選擇NOT IN Query 1中的所有記錄(假設id是表的主鍵,你甚至沒有為lap_data表設置主鍵)

SELECT * FROM lap_data
    WHERE id NOT IN
    (SELECT lt.id 
    FROM (
        SELECT id,Rank() 
        over (Partition BY user_id,track_id
        ORDER BY lap_time ASC ) AS Rank
        FROM lap_data
        WHERE user_id = 1
    ) lt WHERE Rank <= 2) 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM