MySQL-不用窗口函數(shù)實現(xiàn)Rank()Over()功能

眾所周知Mysql8.0之前是不支持窗口函數(shù)的,所以在用到老版本MySQL的時候,如果遇到想分組排序排名之類的需求,可以采用如下方式進行:

設有表employee,數(shù)據(jù)如下(數(shù)據(jù)來自LeetCode):


我們想在A,B,C中分別對Salary這個字段進行排序,可以考慮引入變量來解決這個問題。

之前沒有接觸過MySQL的變量,后來發(fā)現(xiàn)跟PL/SQL有一點不同,變量是需要加@的來賦值。

    SELECT
        em.Id,
        em.Company,
        em.Salary,
    CASE
            @com 
            WHEN em.Company THEN
            @rk := @rk + 1 ELSE @rk := 1 
        END rank1,
    @com := em.Company 
FROM
    employee em,
    ( SELECT @com := '', @rk := 0 ) b 
ORDER BY
    em.Company,
    em.Salary 

其中rk變量是排名,com變量是對應Company切換的。

select里面的case語句意思就是把每一行和com變量比較,如果相同(代表是同一個組別的),那么排名+1,如果不相同(切換了組別),那么排名重置為1。

當然,這么做的前提是,MySQL中實際上order by是在select之前執(zhí)行的。先執(zhí)行關系語句,最后再進行投影,這樣的話,我們先排好序,語句就能按照設想的順序(按照Company和Salary進行排序)來執(zhí)行了。

需要注意的是一點,當語句中有超過兩個關聯(lián)表時,order by的執(zhí)行順序會被放在select之后,這樣達不到排序的效果了,所以一定要先把關聯(lián)表聯(lián)合查詢?yōu)橐粋€臨時表,再進行變量的排序處理!

分步來看,先把CASE語句去掉,直接排序,更容易理解CASE里面的內(nèi)容。

SELECT
    em.Id,
    em.Company,
    em.Salary 
FROM
    employee em,
    ( SELECT @com := '', @rk := 0 ) b 
ORDER BY
    em.Company,
    em.Salary

這個就是單純的排序語句,其中的b表是對變量進行初始化(這也是跟PL/SQL不一樣的地方,需要用select初始化),而且不影響結果,因為跟em表沒有關聯(lián)。
得到的結果如下:


排序結果

然后按照CASE語句走一遍,就很容易理解了。

需要注意的是, @com := em.Company這句話一定要在CASE執(zhí)行完畢之后,這個是把當前處理的行的Company賦值給com變量,用來判斷是否切換了組別。
select中的字段,執(zhí)行是按照順序的。

這樣就能得到最終的結果了:


最終結果

最后看一下SQL語句關鍵字中的執(zhí)行順序(SELECT的順序會隨著SQL的組成調(diào)整進行優(yōu)化,并不固定,我個人理解應該是在ORDER BY后面):

FROM, including JOINs
WHERE
GROUP BY
HAVING
WINDOW functions
DISTINCT
UNION
ORDER BY
SELECT
LIMIT and OFFSET

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容