2016-09-15 46 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

請檢查現在 –