眾所周知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