日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL排名问题

發(fā)布時(shí)間:2023/12/9 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL排名问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • 簡述
    • 第N高薪水(連續(xù)排名,同薪同名)
      • 單表查詢
      • 子查詢方式1
      • 子查詢方式2
      • 自連接
      • 笛卡爾積
      • 自定義變量
      • 開窗函數(shù)
    • 部門前n高薪水(連續(xù)排名,同薪同名)
      • 子查詢方式
      • 連接查詢
      • 自定義變量
      • 開窗函數(shù)

簡述

最近在刷題和工作中總會遇到前n高,第n高的問題,匯總一下以便日后查看。
排名3種場景(以薪水為例):

  • 連續(xù)排名,同薪不同名。3000、2000、2000、1000的排名為1-2-3-4
  • 不連續(xù)排名,同薪同名。3000、2000、2000、1000的排名為1-2-2-4
  • 連續(xù)排名,同薪同名。3000、2000、2000、1000的排名為1-2-2-3
    下面的兩個(gè)例子都以連續(xù)排名,同薪同名的情況舉例

第N高薪水(連續(xù)排名,同薪同名)


如表中所示,如果存在第N高的薪水則返回Salary,如果不存在那么查詢應(yīng)該返回NULL。

單表查詢

  • 解題思路
    全局排名,不分組,所以我們可以用ORDER BY排序加LIMIT N,M限制(M表示在限制條數(shù)之后的offset記錄,LIMIT M OFFSET N),排名第N高意思是LIMIT N-1,1,但是LIMIT后面只接受正整數(shù)或者單一變量,不能用表達(dá)式,所以在函數(shù)中需要先SET N = N - 1
    同薪同名且連續(xù)排名,意味著需要去重,我們可以用GROUP BY 按薪水分組后再ORDER BY或者DISTINCT去重。

MySQL中的LIMIT用法詳解

  • 基本語法:
    SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
  • LIMIT子句用于select中,對輸出結(jié)果集的行數(shù)進(jìn)行約束,LIMIT接受一個(gè)或兩個(gè)數(shù)字參數(shù)。參數(shù)必須是一個(gè)整數(shù)常量。offset表示偏移量(指向數(shù)據(jù)記錄的游標(biāo)),rows表示查詢限定返回的最大記錄數(shù)。當(dāng)offset參數(shù)省略時(shí),默認(rèn)為0,即LIMIT 3 等同于LIMIT 0,3。
    • SELECT * FROM table LIMIT 3, 4;返回第4-7行
    • SELECT * FROM table LIMIT 3;返回前3行


2. 代碼片段

CREATE FUNCTION getNHighestSalary(N INT) RETURNS INT BEGINSET N := N-1;IF (N < 0) THENRETURN NULL;ELSERETURN (SELECT DISTINCT salary FROM employee-- GROUP BY salaryORDER BY salary DESCLIMIT N, 1);END IF; END

子查詢方式1

  • 解題思路
    先查出前n高的薪水,再從中查詢最低的薪水(即第n高的薪水),并用COUNT(1)累加用來判斷是否有第n高的薪水 。考慮會有相等的薪水所以第一重查詢用DISTINCT去重。
  • 代碼片段
  • CREATE FUNCTION getNHighestSalary(N INT) RETURNS INT BEGINRETURN(SELECT IF(count < N, NULL, min) AS SalaryFROM( SELECT MIN(Salary) AS min, COUNT(1) AS countFROM(SELECT DISTINCT SalaryFROM Employee ORDER BY Salary DESC LIMIT N) a) b); END

    子查詢方式2

  • 解題思路
    排名第N高意味著表中存在N-1個(gè)比其更高的薪水(去重前提下)。
    聯(lián)表查詢出比當(dāng)前薪水高的有幾個(gè),如果這個(gè)數(shù)量等于N-1,那么返回該薪水。
  • 代碼片段
  • CREATE FUNCTION getNHighestSalary(N INT) RETURNS INT BEGINRETURN(SELECT DISTINCT(e.salary)FROM Employee eWHERE (SELECTCOUNT(DISTINCT salary)FROM Employee e1 WHERE e1.salary > e.salary) = N - 1); END

    自連接

  • 解題思路
    自連接條件為表1的Salary小于表2的Salary,以表1的Salary分組,統(tǒng)計(jì)表2的Salary的去重個(gè)數(shù)
    考慮到第一名的表2的Salary為空,所以采用LEFT JOIN ,當(dāng)去重個(gè)數(shù)等于N-1時(shí)就是要輸出的排名(也可以用JOIN,連接條件為<=,COUNT(DISTINCT e2.Salary) = N)
  • 代碼片段
  • CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINRETURN (SELECT e1.salaryFROM employee e1 LEFT JOIN employee e2 ON e1.salary < e2.salaryGROUP BY e1.salaryHAVING count(DISTINCT e2.salary) = N - 1); END

    笛卡爾積

  • 解題思路
    跟子查詢方式2相似,不再贅述。
  • 代碼片段
  • CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINRETURN (SELECT e1.salaryFROM employee e1, employee e2 WHERE e1.salary <= e2.salaryGROUP BY e1.salaryHAVING count(DISTINCT e2.salary) = N); END

    自定義變量

  • 解題思路
    自定義兩個(gè)變量,@s存儲工資,@r存儲排名,先按工資排序,查詢時(shí)更新變量值,當(dāng)工資相等時(shí)排名不變,不相等則排名加一
  • 代碼片段
  • CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINRETURN (SELECT DISTINCT salary FROM (SELECT salary, @r:=IF(@s=salary, @r, @r+1) AS rnk, @s:= salary FROM employee, (SELECT @r:=0, @s:=NULL)init ORDER BY salary DESC) tmpWHERE rnk = N); END

    開窗函數(shù)

  • 解題思路
    mysql8.0以上版本可以用開窗函數(shù),效率是最好的,常用的三種排名函數(shù)如下:
    • ROW_NUMBER():連續(xù)排名,同薪不同名,3000、2000、2000、1000的排名為1-2-3-4
    • RANK(): 不連續(xù)排名,同薪同名。3000、2000、2000、1000的排名為1-2-2-4
    • DESENSE_RANK():連續(xù)排名,同薪同名。3000、2000、2000、1000的排名為1-2-2-3
      這三個(gè)函數(shù)要和OVER()一起使用,OVER()中的參數(shù)通常是PARTITION BY 和 ORDER BY 。例題情況是第三種,所以采用DENSE_RANK()。
  • 代碼示例
  • CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINRETURN (SELECT DISTINCT salaryFROM (SELECT salary, dense_rank() over(ORDER BY salary DESC) AS rnkFROM employee) tmpWHERE rnk = N); END

    部門前n高薪水(連續(xù)排名,同薪同名)



    如表中所示,如果存在部門前N高的薪水則返回DepartmentId + Salary,如果不存在那么查詢應(yīng)該返回NULL。因?yàn)橹豢紤]部門和薪水,所以還是連續(xù)排名,同薪同名。

    子查詢方式

  • 解題思路(和第N高薪水的子查詢方式2類似)
    工資前N高意味著:有不超過N-1個(gè)人的工資比查詢結(jié)果的工資高。例如求前三高的工資,即有不超過2個(gè)人(查詢子條件為<=2或<3)的工資比查詢結(jié)果的工資高(有0個(gè)人比第一高工資高;有1個(gè)人比第二高工資高;有2個(gè)人比第三高工資高)
  • 代碼示例
  • SELECTd.Name AS 'Department', e1.Name AS 'Employee', e1.SalaryFROM Employee e1RIGHT JOIN Department d ON e1.DepartmentId = d.IdWHERE3 > (SELECT COUNT(DISTINCT e2.Salary)FROM Employee e2WHERE e2.Salary > e1.SalaryAND e1.DepartmentId = e2.DepartmentId) GROUP BY e1.SalaryORDER BY d.`Name`, e1.Salary DESC ;

    連接查詢

  • 解題思路
    能用子查詢解決的問題一般都能用連接來解決
  • 代碼示例
  • SELECTd.name as department, e1.name as employee, e1.salary as salaryFROMDepartment d LEFT JOIN Employee e1 on d.id = e1.departmentidLEFT JOIN Employee e2 on e1.departmentid = e2.departmentid and e1.salary<=e2.salaryGROUP BY d.name, e1.SalaryHAVING count(distinct e2.salary)<4ORDER BYd.name, e1.salary DESC

    自定義變量

  • 解題思路
    自定義三個(gè)變量,@s存儲工資,@r存儲排名,@d存儲部門ID,先按部門和工資排序,查詢時(shí)更新變量值。
    (1)當(dāng)前部門ID與@d相同(@d=DepartmentId),則代表是在同一部門中進(jìn)行的排名,當(dāng)工資相等(@s=Salary)時(shí)排名不變(@r:=@r),不相等則排名加一(@r:=@r+1);
    (2)當(dāng)前部門ID與@d不相同(@d!=DepartmentId),則說明@d需重新賦值(@d=DepartmentId),排名也要重新開始,即@r:=1。
  • 代碼示例
  • SELECTd. NAME department,t. NAME employee,salaryFROM(SELECT*, @r :=IF (DepartmentId = @d, IF (Salary = @s, @r, @r + 1), 1) AS rnk,@d := DepartmentId,@s := SalaryFROM employee, (SELECT @s := NULL,@d := NULL, @r := 0 ) initORDER BY DepartmentId, Salary DESC) tRIGHT JOIN department d ON t.DepartmentId = d.IdWHERE t.rnk <= N OR t.rnk IS NULLGROUP BY d.`Name`, salaryORDER BY DepartmentId, Salary DESC

    開窗函數(shù)

  • 解題思路
    又到了快樂的開窗函數(shù),因?yàn)槭峭酵?#xff0c;連續(xù)排名,所以還是用DENSE_RANK(),因?yàn)榍蟮氖遣块T前N高薪水,所以按部門分組再按薪水排序,那么開窗函數(shù)的使用就是:DENSE_RANK() OVER(PARTITION BY departmentid ORDER BY salary DESC) 。
  • 代碼示例
  • SELECTd.`Name`, tmp.`Name`, tmp.Salary FROM(SELECT e1.DepartmentId, e1.`Name`, e1.Salary,DENSE_RANK() OVER(PARTITION BY e1.DepartmentId ORDER BY e1.Salary DESC) rnkFROM employee e1 ) tmpRIGHT JOIN department dON d.Id = tmp.DepartmentIdWHERE rnk <= N OR t.rnk IS NULLGROUP BY d.name, tmp.Salary;

    總結(jié)

    以上是生活随笔為你收集整理的MySQL排名问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。