转载于:https://www.cnblogs.com/contixue/p/7057025.html

Write a SQL query to get the second highest salary from the Employee table.

+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+

For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null

+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+

Subscribe to see which companies asked this question.

翻译:

题目的意思是,在Employee表中找到第二大的Salary字段,然后以别名“SecondHighestSalary ”的形式输出

解题思路:

本题有两种思路。

一种是找到找到最大值,然后我们取比最大值小一点的最大值。

SQL:

SELECT Max(Salary) as SecondHighestSalary FROM Employee WHERE Salary< ( SELECT  Max(Salary) FROM Employee);

Max()函数表示返回最大值,如果没有最大值则返回NULL

Salary<( SELECT Max(Salary) FROM Employee) 则是子查询的概念。

例如 Select * From Table_A Where key in (a,b);  如果其中(a,b)的数据来源于Table_B或者Table_A表。我们就可以使用子查询,将(a,b)的数据替换为我们查询到的数据。

Select * From Table_A Where key in (Select a,b From Table_B  Where Inr='XXXXXXX');

“as XXX”则表示将输出的数据以“XXX”为别名的方式输出。

 

还有一种方法就是,我们将数据进行排序,然后取第二位数。

这种方法的难点在于:1、数据可能会有重复项。

          2、需要先排序再取数,所以不能用between 方法因为between方法必须要在order by 之前。

          3、整个表都是同一个数据的极端情况。

对于情况3容易产生的错误写法:

select Salary SecondHighestSalary from employee
order by salary limit 1,1

  要解决以上3个难点。我们首先使用DISTINCT方法将数据的重复项过滤只剩一条,然后使用LIMIT分页的方法取第二个值,对于情况3中的极端情况,我们使用IFNULL来进行判断,如果没取到值就返回NULL。

  需要注意的是,LIMIT是MySQL中的用法,Oracle是不支持LIMIT的。

SQL:

SELECT IFNULL( (SELECT distinct Salary  FROM Employee order by Salary desc limit 1,1),null)as SecondHighestSalary;

其中LIMIT 的用法是这样的:

LIMIT m,n      "m"表示偏移量,表示从第几位开始取。"n"表示长度,即需要取多少位。

需要注意的是偏移量的第一位为0,所以"LIMIT 1,1"表示从第二位开始取长度为1的数也就是第二位数。

"LIMIT 0,n"或者"LIMIT n "则表示从第一位开始取,一直取到第n位为止。"LIMIT m,-1"表示从第m位开始取,一直取到表的末尾。

distinct 表示将查询到的结果过滤重复项,只保留一项。

IFNULL(Exp1,Exp2),类似一个三元表达式,如果Exp1不为空则返回Exp1的结果集,如果为空就返回Exp2.

方法二的关键点在于排序和取数,排序我们除了使用ORDER BY 方法之外,还可以使用比较的方式排序。

SQL:

SELECT DISTINCT(e2.Salary) FROM Employee e1,Employee e2 WHERE e2.Salary>=e1.Salary;

使用“>=”的方式,是为了避免Salary字段有0值而导致无法比较

(sql空值表示:

在允许空值的情况下,空值是NULL(null在表中为字符串类型),指没有填写过数据;
在不允许为空的情况下,数值型字段默认为0)

需要注意的是,这种排序方式非常非常的消耗系统资源,在实际生产中使用这种方式来排序是不负责任的行为(见https://www.cnblogs.com/MarsDing/p/9856272.html),所以如非必要尽量不要使用这种方式而使用更快捷消耗更小的的Order by。

现在已经排好序了,那么接下来我们要进行取数。取数可以使用上面的LIMIT方法。

LIMIT方法:

SELECT IFNULL((SELECT DISTINCT(e2.Salary) FROM Employee e1,Employee e2 WHERE e2.Salary>e1.Salary LIMIT 1,1),NULL) as SecondHighestSalary;

即,将:order by Salary desc 替换为 WHERE e2.Salary>e1.Salary

除此之外还有其他方法吗?我们知道,SELECT语句实际上是个循环语句,既然是个循环语句而且已经排好序,那么也就是说如果我们要取第二大的数据,我们可以取当他循环到第二次时的那一行。怎么取到那一行呢。学过For循环都知道,要先对这个循环进行计数,然后循环到我们需要的那一次再取值。那么SQL中怎么计数呢。答案是使用COUNT方法。

COUNT方法

SELECT e1.Salary FROM Employee e1 WHERE 2=(Select Count(distinct(e2.Salary)) from Employee e2 where e2.Salary >= e1.Salary)  as SecondHighestSalary;

上面两种方法也可以用于,取任意第N位数据时。

COUNT方法之所以不能使用Order by,是因为Order by是对结果进行排序,而我们需要的是已排序好的结果。

如果要使用Order by 方法,需要再加一层子查询。

COUNT-Order By 方法

SELECT Salary FROM Employee  WHERE 2=(Select Count(distinct(Salary)) from (Select Salary From Employee order by Salary desc))  as SecondHighestSalary;

.

由于Oracle中不能使用LIMIT,所以我们用rownum来处理此问题

Select Salary from (select amt ,rownum n From (Select distinct amt from Employee order by Salary desc)) where n=2;

其中的n=2可以替换为任意正整数,即为第N位。

总结:对一个题可以通过不同角度思考并优化解答,这需要长期不断地积累各种知识点并汇总结合

【LeetCode刷题】SQL-Second Highest Salary 及扩展以及Oracle中的用法的更多相关文章

  1. LeetCode刷题专栏第一篇--思维导图&时间安排

    昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...

  2. leetcode 刷题进展

    最近没发什么博客了 凑个数 我的leetcode刷题进展 https://gitee.com/def/leetcode_practice 个人以为 刷题在透不在多  前200的吃透了 足以应付非算法岗 ...

  3. LeetCode刷题指南(字符串)

    作者:CYC2018 文章链接:https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode+%E9%A2%98%E8%A7% ...

  4. leetcode刷题记录--js

    leetcode刷题记录 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但 ...

  5. LeetCode刷题总结之双指针法

    Leetcode刷题总结 目前已经刷了50道题,从零开始刷题学到了很多精妙的解法和深刻的思想,因此想按方法对写过的题做一个总结 双指针法 双指针法有时也叫快慢指针,在数组里是用两个整型值代表下标,在链 ...

  6. Leetcode刷题记录(python3)

    Leetcode刷题记录(python3) 顺序刷题 1~5 ---1.两数之和 ---2.两数相加 ---3. 无重复字符的最长子串 ---4.寻找两个有序数组的中位数 ---5.最长回文子串 6- ...

  7. LeetCode刷题总结-数组篇(上)

    数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...

  8. LeetCode刷题总结-数组篇(中)

    本文接着上一篇文章<LeetCode刷题总结-数组篇(上)>,继续讲第二个常考问题:矩阵问题. 矩阵也可以称为二维数组.在LeetCode相关习题中,作者总结发现主要考点有:矩阵元素的遍历 ...

  9. LeetCode刷题总结-数组篇(下)

    本期讲O(n)类型问题,共14题.3道简单题,9道中等题,2道困难题.数组篇共归纳总结了50题,本篇是数组篇的最后一篇.其他三个篇章可参考: LeetCode刷题总结-数组篇(上),子数组问题(共17 ...

随机推荐

  1. UVAlive-7040 color(组合数学,二项式反演)

    链接:vjudge 题目大意:有一排方格共 $n$ 个,现在有 $m$ 种颜色,要给这些方格染色,要求相邻两个格子的颜色不能相同.现在问恰好用了 $k$ 种颜色的合法方案数.答案对 $10^9+7$ ...

  2. OAuth2的基本概念的理解

    书籍推荐 OAuth2 in Action -- 原理 OAuth2 Cookbook -- 实践 OAuth2 解决的问题域 开放系统间授权 社交联合登录 开放API平台 现代微服务安全 单页浏览器 ...

  3. 【CF61D】Eternal Victory

    题目大意:给定一棵 N 个节点的树,求从 1 号节点(根节点)出发,任意节点结束,且至少经过每个节点一次的最短路径是多少. 题解:首先考虑最终要回到根节点的情况,可以发现最短路径长度一定等于该树边权的 ...

  4. c/c++ 判断两个实型的关系

    etc. minv=1e-10 or less x>y : x>y-minv x<y : x<y+minv x=y : fabs(x-y)<minv

  5. Hadoop生态圈-Azkaban部署实战

    Hadoop生态圈-Azkaban部署实战 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.Azkaban部署流程 1>.上传azkaban程序并创建解压目录 [yinz ...

  6. Java访问权限控制

    访问权限控制           java提供了访问权限修饰词,以供类库开发人员向客户端程序员指明哪些是可用的,哪些是不可用的.访问权限控制的等级,从最大权限到最小权限依次是:public.prote ...

  7. SQL记录-PLSQL集合

    PL/SQL集合 集合是一个有序组具有相同的数据类型的元素.每个元素进行标识的唯一标表示其在集合中的位置. PL/SQL提供了三种集合类型: 索引表或关联数组 嵌套表 可变大小的数组或变长数组 Ora ...

  8. Codeforces 295 B. Greg and Graph

    http://codeforces.com/problemset/problem/295/B 题意: 给定一个有边权的有向图.再给定一个1~n的排列. 按排列中的顺序依次删除点,问每次删除后,所有点对 ...

  9. 2018年11月25日ICPC焦作站参赛总结

    可能就这么退役了吧. 对这次ICPC还是比较有信心的,毕竟心态都放平和了. 路途很波折,热身赛还是赶上了. 等到了正赛的时候,开场看出了A题的签到,签到肯定是我来签的,11分钟签完了这道题之后,开始看 ...

  10. ant+sonar+jacoco代码质量代码覆盖率扫描

    使用ant构建的java web项目如何做sonar代码质量扫描?以下就是实际遇到并成功使用的案例一.做sonar扫描的准备工作    1.给web项目增加build.xml构建脚本.    2.下载 ...