我在這篇博客https://www.cnblogs.com/chendongblog/p/11887712.html中說過,
在 sql server中outer apply / cross apply 可以更高效率的實現跟row_number函數同等的功能
但mysql 5.7 不僅outer apply / across apply 沒有, row_number也沒有. 哭 !
聽說mysql 8.0 版本 也可以使用row_number函數了
但我們使用的是5.7版本
網上的資料很多, 但感覺不夠簡潔明了, 所以決定自己寫一下
SELECT * FROM ( SELECT @rn:= CASE WHEN @securityid = securityid THEN @rn + 1 ELSE 1 END AS rn, @securityid:= securityid as securityid, volume, date FROM (SELECT * from us_historicaldaily WHERE DATE <= '2019-05-16' ORDER BY securityid, date DESC) a ,(SELECT @rn=0, @securityid=0) b )a WHERE rn <= 5
這里有幾點解釋下:
1. 這里對表分組的依據是securityid, 排序的依據是date
相當於有個指針在從上往下滑動, 需要一個用戶變量@securityid來記錄最近一次securityid的值,
然后跟當前行的securityid列做對比, 如果相等(@securityid = securityid) 說明當前在同一個分組中, @rn 遞增1 ,
否則說明當前組已經變更了 @rn重新計數, 從1開始
2. a表中order by 是必須的, 因為只有排序的表從上往下遍歷才有意義,
而且order by的字段順序要相當於row_number函數的 partition by securityid order by date desc
由於sql的執行順序, order by 排在select 之后, 所以order by語句必須寫在a表中, 而不是整個sql的末尾(恰好mysql支持order by語句寫在表中)
3. b表也是必須的, b表相當於在a表后面加兩個字段初始化這兩個變量的值, 也可以用set關鍵字初始化, 但我還是喜歡用表.
結果如下