2016-09-15 45 views
3

我已经过单场发现了最新/最单列存在的问题在几个领域,或最近n行分组,而不是两人在一起MySQL的 - 选择前n行,2列

我需要构造2次的查询,使用(类似于this question

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:

  • 我要上2结果通过lap_time - 每磁道,每个用户
    • 所以如果一个给定的user_id有20条记录分布在3个轨道...
      • 我希望6个结果该USER_ID
      • 或5如果这些轨道中的一个只有
    • 在2个不同轨道上的同一圈时间都应该被显示的单个记录,不会出现仅一次
  • 我想使用WHERE USER_ID IN(..),用于通过给定的字段排序部1
  • ,即lap_time
  • 其中lap_status = 1

这是查询我我一直在别处用来收集给定类型的两个最新记录,这是最接近我认为我需要的,修改为这个例子..虽然未完成,如在另一个例子中,它只收集最近的两个行每个user_id ..在这里我需要它也考虑到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:

  • 我想要得到的上述逆,对于单个用户
    • 即,除f以外的其余结果开始步骤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 | 

任何建议?谢谢!

+0

你试过什么了吗? –

+0

@Strawberry增加了信息家伙,感谢提示我 –

+0

你的努力看起来非常接近 - 你确定你不知道如何适应? – Strawberry

回答

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 
+0

感谢张贴另一个版本..不幸的是,这返回4行user_id = 1和track_id = 2 –

+0

好吧,我忘了分配prevTrackId和prevUserId当前行。试试上面编辑的代码。 – darrell

+0

我仍在检查各种使用情况,但这看起来像是做这项工作......非常感谢! –

-1

查询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查询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) 
+0

非常感谢我在第一个查询中遇到错误:您的SQL语法出错;检查与你的MySQL服务器版本相对应的手册,以便在''(分区BY user_id,track_id ORDER BY lap_time ASC)附近使用正确的语法作为排名从第4行la' –

+0

哈,对不起,我提供的解决方案在MSSQL而不是MySQL,我的坏。 – darrell

0

该查询使得一个重要的(而且很可能是错误的)假设 - 这就是hi先前用户的最高track_id高于(或至少不同于)下一个用户的最低track_id。

如果不是的话,那么你可能需要另一个变量,或基地“下一页”存储在两个值的串联......

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:[email protected]+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; 
+0

谢谢你.. track_id可能是相同或不同的不幸,也就是说,可能有多个用户都只有第2轨的记录,例如...存储另一个值并将它们连接成prev,这可能是最快? –

+0

不管 - 但是我发现这个逻辑更容易编写为嵌套的IF,而不是嵌套的CASE语句 – Strawberry

+0

我可以麻烦你发布带有两个字段的查询作为用户定义的值吗?我不知道如何处理它.....(我实际上惊呆了,我设法正确地猜测要么prev需要连接,或跟踪两个领域) –

0
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 
+0

这将返回四行与track_id = 2和user_id = 1 ..我只想要两行 –

+0

请检查现在 –