欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Leetcode SQL(五)

程序员文章站 2022-06-10 22:16:51
...

 

177. 第N高的薪水

https://leetcode-cn.com/problems/nth-highest-salary/

Leetcode SQL(五)

题解

一:dense_rank函数。

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  RETURN (
      # Write your MySQL query statement below.
     select distinct Salary from 
     (select Salary, dense_rank() over (order by Salary desc) as cnt 
      from Employee)a where cnt = N
  );
END

二:这边mark一下一位大神的题解,转自https://leetcode-cn.com/problems/nth-highest-salary/solution/mysql-zi-ding-yi-bian-liang-by-luanz/

排名是数据库中的一个经典题目,实际上又根据排名的具体细节可分为3种场景:

  1. 连续排名,例如薪水3000、2000、2000、1000排名结果为1-2-3-4,体现同薪不同名,排名类似于编号
  2. 同薪同名但总排名不连续,例如同样的薪水分布,排名结果为1-2-2-4
  3. 同薪同名且总排名连续,同样的薪水排名结果为1-2-2-3

不同的应用场景可能需要不同的排名结果,也意味着不同的查询策略。本题的目标是实现第三种排名方式下的第N个结果,且是全局排名,不存在分组的问题,实际上还要相对简单一些。

值得一提的是:在Oracle等数据库中有窗口函数,可非常容易实现这些需求,而MySQL直到8.0版本也引入相关函数。当前MySQL OJ系统为5.7版本(可通过编码区——语言选择按钮——左侧的"i"查看环境信息),所以不能直接应用。

至此,可以总结MySQL查询的一般性思路是:

  1. 能用单表优先用单表,即便是需要用group by、order by、limit等,效率一般也比多表高
  2. 不能用单表时优先用连接,连接是SQL中非常强大的用法,小表驱动大表+建立合适索引+合理运用连接条件,基本上连接可以解决绝大部分问题。但join级数不宜过多,毕竟是一个接近指数级增长的关联效果
  3. 能不用子查询、笛卡尔积尽量不用,虽然很多情况下MySQL优化器会将其优化成连接方式的执行过程,但效率仍然难以保证
  4. 自定义变量在复杂SQL实现中会很有用,例如LeetCode中困难级别的数据库题目很多都需要借助自定义变量实现
  5. 如果MySQL版本允许,某些带聚合功能的查询需求应用窗口函数是一个最优选择。除了经典的获取3种排名信息,还有聚合函数、向前向后取值、百分位等,具体可参考官方指南。以下是官方给出的几个窗口函数的介绍:

Leetcode SQL(五)

最后的最后再补充一点,本题将查询语句封装成一个自定义函数并给出了模板,实际上是降低了对函数语法的书写要求和难度,而且提供的函数写法也较为精简。然而,自定义函数更一般化和常用的写法应该是分三步:

  1. 定义变量接收返回值
  2. 执行查询条件,并赋值给相应变量
  3. 返回结果

由于本题不存在分组排序,只需返回全局第N高的一个,所以自然想到的想法是用order by排序加limit限制得到。需要注意两个细节:

  1. 同薪同名且不跳级的问题,解决办法是用group by按薪水分组后再order by
  2. 排名第N高意味着要跳过N-1个薪水,由于无法直接用limit N-1,所以需先在函数开头处理N为N=N-1。

注:这里不能直接用limit N-1是因为limit和offset字段后面只接受正整数(意味着0、负数、小数都不行)或者单一变量(意味着不能用表达式),也就是说想取一条,limit 2-1、limit 1.1这类的写法都是报错的。
注:这种解法形式最为简洁直观,但仅适用于查询全局排名问题,如果要求各分组的每个第N名,则该方法不适用;而且也不能处理存在重复值的情况。

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
    SET N := N-1;
  RETURN (
      # Write your MySQL query statement below.
     select Salary from Employee group by Salary
     order by Salary desc limit N,1
  );
END

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关标签: leetcode SQL