分組數據篩選(group by后取出每組的第n條數據)


    今天在一個群里有人問一個問題,如何在msql里執行一個查詢:從一個表里面取數據,按照某個字段分組,然后取每組的第三條數據。有個人說了oracle的實現方法,用到了rank。當然,oracle我是不懂的,google的結果是mysql里面也沒有rank函數。然后搜到了一篇文章研究了一下,總算折騰出來了。下面是參考文章的鏈接:http://blog.sina.com.cn/s/blog_4d18beb10100y3kt.html

    先創建一個表作為例子:   

1 CREATE TABLE sam (
2   `a` int(11) DEFAULT NULL,
3   `b` int(11) DEFAULT NULL
4 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
5 INSERT INTO sam VALUES (1,10),(1,15),(1,20),(1,25),(2,20),(2,22),(2,33),(2,45);

表里的數據如下:
a b
1 10
1 15
1 20
1 25
2 20
2 22
2 33
2 45
    
然后就是一個查詢,給每組的行都加上序號:    

1 SELECT a,b,
2     @rank:=IF(@a=a, @rank+1, 1) rank,
3     @a:=a 
4     FROM `sam`,
5     (SELECT @rank:=1,@a:=null) tt;

    查詢結果:          

a b rank @a:=a
1 10 1 1
1 15 2 1
1 20 3 1
1 25 4 1
2 20 1 2
2 22 2 2
2 33 3 2
2 45 4 2

    這里有些地方需要解釋一下。
    第1行:這里用到了用戶變量和IF函數,用戶變量就是每次查詢的臨時變量,類似java方法里面的臨時變量。IF函數類似if語句,里面有三個參數,第一個是條件,第二個是條件成功時的返回值,第三個是條件失敗時的返回值。
    第3行:這里保存一下a列的值,用來跳轉到下一行時在IF里面和最新a值做對比,以便決定rank是否需要重置為1。
    第5行,這里其實啥都沒干,主要作用類似聲明變量,反正不聲明結果會很詭異,詳細原因還沒研究清楚。

    綜上所述,取每組第三行的查詢語句是:    

1 SELECT t.a, t.b FROM (SELECT a,b,@rank:=IF(@a=a, @rank+1, 1) rank,@a:=a FROM sam) t,
2     (SELECT @rank:=1,@a:=null) tt WHERE rank=3;

   查詢結果:   

a b
1 20
2 33

  上面沒有考慮順序,因為原始數據本來就是有順序的。如果考慮到a、b的順序以及b可能有重復值,可以使用下面的語句,讀者可以插入幾條重復數據測試一下:    

SELECT t.a, t.b FROM (SELECT f.a,f.b,
    @rank:=IF(@b<>f.b,IF(@a=f.a, @rank+1, 1),@rank) rank,
    @a:=f.a,
    @b:=f.b
    FROM (SELECT a,b FROM `SAM` ORDER BY a,b) f,
    (SELECT @rank:=1,@a:=null,@b:=null) tt) t WHERE rank=3;

 

    
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM