各種排序問題的綜合應用
對MySQL基礎上機練習題(二)中所輸入的數據進行排序
拿數組(56,56,67,67,67,78,79,80)來說,可以形成三種排列: (1)即使值相同,也會不會排在同一位:(1,2,3,4,5,6,7,8,) (2)值相同的在同一位,但不占位:(1,1,2,2,2,3,4,5) (3)值相同的在同一位,但占位:(1,1,3,3,3,6,7,8)
這里的@rowNum 是自定義的一個變量,@rowNum := @rowNum+1 代表一個首項為0,等差為1的自增列r,每查詢到一個InCome(即薪水),就會@rowNum這個變量就會遞增1,放到r這個自增列中。 也可以簡單地把(SELECT @rowNum := 0)r看成是一個新的表,整體的查詢相當于在Salary這個原來的表與新的r表進行復合表查詢 但使用這種方法,在遇到薪酬水平相同時,會出現排位不相同的現象 
如圖中第一名與第二名的薪水相同但排名不一致
當需要對相同值進行相同排序時,可以使用多一個變量來使得相同薪酬水平的人排位是一致的
SELECT EmployeeID, InCome, @rowNum := @rowNum + (@PRev <> (@prev := InCome)) RankFROM Salary, (SELECT @rowNum := 0, @prev := -1) initORDER BY InCome desc這里的@prev變量是用作對比前一個InCome和下一個InCome是否一致,(@prev <>(@prev:=InCome))的作用在于判斷是否需要給@rowNum遞增一位: ①如果前一個員工的InCome的薪酬水平和當前查詢的員工的InCome薪酬水平是相同的,那么@prev<>(@prev:=InCome)會返回FALSE,即0,那么當前員工的排位就會與前一個員工排位一樣; ②如果前一個員工的薪酬水平(InCome)和后一個員工的薪酬水平(InCome)不相同,那么@prev<>(@prev:=InCome)會返回TRUE,即1,那么當前員工的排位就會比前一個員工的排位多1;  在圖中可以看出,第一名有兩位,第二、三…名繼續往后排
 在圖中可以看出,第一名有兩位,第二、三…名繼續往后排
也存在某些情況,值相同時,排位相同,但接下來的排位按照正常排序排列,就拿數組(56,56,67,67,67,78,79,80)來說,可以形成占位排序:(1,1,3,3,3,6,7,8);此時需要根據上一題作出一些調整,多生成一個變量
SELECT InCome, Rank FROM(SELECT InCome, @rowNum := @rowNum + 1, CASE WHEN @prev = InCome THEN @rank := @rank WHEN @prev <> (@prev := InCome) THEN @rank := @rowNum END AS RankFROM Salary, (SELECT @rowNum := 0, @prev := (SELECT InCome FROM Salary ORDER BY InCome DESC LIMIT 0,1), @rank := 1) initORDER BY InCome DESC)T這里存在三個變量,前兩個變量與第二題一樣,@rowNum是用作作為遞增列,@prev是用作對比前后值是否一致,而增加@rank變量的具體思路是: ①如果前一名員工與當前員工的薪酬水平不一致,@rank會與@rowNum的值一致,一直遞增,返回給Rank ②如果前一名員工與當前員工的薪酬水平一致,@rank會返回當前@rank的值,無論有多少個員工的薪酬水平一致,都會返回相同的@rank值給Rank 因此可以寫出這樣一個條件語句:
CASE WHEN @prev = InCome THEN @rank := @rank WHEN @prev <> (@prev := InCome) THEN @rank := @rowNum END AS Rank而同時需要注意的是@prev的初始值應該是按照薪酬水平降序排列的第一條記錄值:
@prev := ( SELECT InCome FROM Salary ORDER BY InCome DESC LIMIT 0,1)
這個是稍微復雜一點的嵌套查詢,由于Mysql的GROUP BY函數只能返回1行,所以需要用到其他方法去達到組內排名的目的。 首先子查詢如下:
SELECT COUNT(DISTINCT(E.WorkYear)) FROM Employees AS E WHERE E.DepartmentID = Employees.DepartmentID AND Employees.WorkYear < E.WorkYear這個子查詢是當外層查詢查詢到一個Employees表中的一行數據(假設為A)時,會傳遞當前行的數據到子查詢中,使得子查詢遍歷部門號與當前數據部門號(A.DepartmentID)相同的數據,查詢到遍歷表中每一行數據與當前數據的工作年齡(A.WorkYear)相比更大的行有多少條 以圖表的形式解釋:  ①假設當前外層查詢到第一行(1,“張揚“, 2),那么會傳遞到子查詢中,與部門編號都為1的員工比較工齡,可以看出有4位員工的工齡是比張揚要大的。 ②假設當前外層查詢到第四行(1,“李麗”,6),那么會傳遞到子查詢中,與部門編號都為1的員工比較工齡,可以看出沒有員工(0<2)的工齡比李麗要大的,那么李麗的這條數據符合條件,會輸出到外層的查詢中;
 ①假設當前外層查詢到第一行(1,“張揚“, 2),那么會傳遞到子查詢中,與部門編號都為1的員工比較工齡,可以看出有4位員工的工齡是比張揚要大的。 ②假設當前外層查詢到第四行(1,“李麗”,6),那么會傳遞到子查詢中,與部門編號都為1的員工比較工齡,可以看出沒有員工(0<2)的工齡比李麗要大的,那么李麗的這條數據符合條件,會輸出到外層的查詢中;
外層
SELECT DepartmentName, Name, WorkYearFROM Employees LEFT JOIN departments USING(DepartmentID)WHERE(#子查詢) < 2 ORDER BY DepartmentID, WorkYear此層子查詢用于判斷數據的條數是否符合條件,接上文中子查詢: ①當由于第一行(1,“張揚“, 2)最終輸出4,4>2,那么張揚這條數據就不符合條件,不會輸出; ②當由于第四行(1,“李麗”,6)最終輸出0,0<2,那么李麗的這條數據符合條件,會輸出結果;

具體的思路和第2題是一致的,但是由于要連接3個表,看起來有點復雜,但是其實是一樣的做法:
SELECT D.DepartmentName, E.Name, S.InCome FROM Employees EJOIN Salary S USING(EmployeeID)JOIN Departments D USING(DepartmentID)WHERE( SELECT COUNT(DISTINCT(S2.InCome)) FROM Employees E2 JOIN Salary S2 USING(EmployeeID) WHERE S2.InCome > S.InCome AND E.DepartmentID = E2.DepartmentID) < 3 ORDER BY E.DepartmentID首先,從子查詢入手:
SELECT COUNT(DISTINCT(S2.InCome)) FROM Employees E2 JOIN Salary S2 USING(EmployeeID) WHERE S2.InCome > S.InCome AND E.DepartmentID = E2.DepartmentID由于薪資和員工不在同一個表中,所以子查詢中需要用連接來查詢;這個子查詢是當外層查詢查詢到一個Employees表、Salary表的復合表(假設表T)中的一行數據(假設為B)時,會傳遞當前行的數據到子查詢中,使得子查詢遍歷部門號與當前數據部門號(B.DepartmentID)相同的數據,查詢到遍歷表中每一行數據與當前數據的薪酬(B.InCome)相比更大的行有多少條 以圖表的形式解釋:  上圖為DepartmentID=’1’時的表T(Employees和Salary表的復合表) ①假設外層查詢得到第一行數據(“1”,“張揚”,5633.00),那么會傳遞到子查詢中,與部門編號都為1的員工比較薪水,可以看出有2位員工的薪酬是比張揚的薪酬要高的。 ②假設外層查詢到第二行數據(“1”,“伍容華”,2100.80),那么會傳遞到子查詢中,與部門編號都為1的員工比較薪水,可以看出有5位員工的薪酬是比張揚的薪酬要高的。
 上圖為DepartmentID=’1’時的表T(Employees和Salary表的復合表) ①假設外層查詢得到第一行數據(“1”,“張揚”,5633.00),那么會傳遞到子查詢中,與部門編號都為1的員工比較薪水,可以看出有2位員工的薪酬是比張揚的薪酬要高的。 ②假設外層查詢到第二行數據(“1”,“伍容華”,2100.80),那么會傳遞到子查詢中,與部門編號都為1的員工比較薪水,可以看出有5位員工的薪酬是比張揚的薪酬要高的。
外層查詢:
SELECT D.DepartmentName, E.Name, S.InCome FROM Employees EJOIN Salary S USING(EmployeeID)JOIN Departments D USING(DepartmentID)WHERE(#子查詢) < 3ORDER BY E.DepartmentID此層子查詢用于判斷數據的條數是否符合條件,接上文中子查詢: ①當由于第一行(”1”,”張揚”, 2)最終輸出2,2<3,那么張揚這條數據就符合條件,會輸出; ②當由于第二行(”1”,”伍容華”,2100.80)最終輸出5,5>2,那么伍容華的這條數據不符合條件,不會輸出結果;
(1)即使值相同,也會不會排在同一位:(1,2,3,4,5,6,7,8,) (2)值相同的在同一位,但不占位:(1,1,2,2,2,3,4,5) (3)值相同的在同一位,單占位:(1,1,3,3,3,6,7,8)
新聞熱點
疑難解答