LeetCode刷题笔记 - 177. Nth Highest Salary

2018-10-11

177. Nth Highest Salary


一、Description:

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

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

For example, given the above Employee table, the nth highest salary where n = 2 is 200. If there is no nth highest salary, then the query should return null.

+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| 200                    |
+------------------------+

** 二、Solution:**

解法一:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  declare M INT;  
  set M=N-1;
  RETURN (
      select distinct Salary 
      from Employee
      order by Salary DESC
      limit M,1
  );
解法二:

三、总结知识点

(转载)原文:https://www.cnblogs.com/progor/p/8871480.html

1.MYSQL之自定义函数function

什么是函数:

  • 函数存储着一系列sql语句,调用函数就是一次性执行这些语句。所以函数可以降低语句重复。【但注意的是函数注重返回值,不注重执行过程,所以一些语句无法执行。所以函数并不是单纯的sql语句集合。】
  • mysql函数有自己的自定义函数(已经定义好了的函数),参考下文
  • 这里主要介绍如何自定义函数。
  • 函数与存储过程的区别:函数只会返回一个值,不允许返回一个结果集。函数强调返回值,所以函数不允许返回多个值的情况,即使是查询语句。
-- 不行的代码:Not allowed to return a result set from a function
create function myf()returns int 
begin
select * from student;
return 100;
end;

函数的创建:

  • 语法:
create function 函数名([参数列表]) returns 数据类型
begin
 sql语句;
 return 值;
end;

参数列表的格式是: 变量名 数据类型

  • 示例:
-- 最简单的仅有一条sql的函数
create function myselect2() returns int return 666;
select myselect2(); -- 调用函数

--
create function myselect3() returns int
begin 
    declare c int;
    select id from class where cname="python" into c;
    return c;
end;
select myselect3();
-- 带传参的函数
create function myselect5(name varchar(15)) returns int
begin 
    declare c int;
    select id from class where cname=name into c;
    return c;
end;
select myselect5("python");
  • 还可以有一些特别的选项,特别的选项写在return 之后,begin之前,如:
  • comment:一个关于函数的描述
  • 还有一些比如sql security等选项,有兴趣可以自行百度。这里不讲解,仅一提有此知识点。

函数的调用:

  • 直接使用函数名()就可以调用【虽然这么说,但返回的是一个结果,sql中不使用select的话任何结果都无法显示出来(所以单纯调用会报错),
  • 如果想要传入参数可以使用函数名(参数)
  • 调用方式【下面调用的函数都是上面中创建的。】:
-- 无参调用
select myselect3();
-- 传参调用
select myselect5("python");
select * from class where id=myselect5("python");

函数的查看:

  • 查看函数创建语句:show create function 函数名;
  • 查看所有函数:show function status [like ‘pattern’];

函数的修改:

  • 函数的修改只能修改一些如comment的选项,不能修改内部的sql语句和参数列表。
  • alter function 函数名 选项;

函数的删除:

  • drop function 函数名;

2.MYSQL之常用函数

mysql函数的介绍:

  • 为了简化操作,mysql提供了大量的函数给程序员使用(比如你想输入当前时间,可以调用now()函数)
  • 函数可以出现的位置:插入语句的values()中,更新语句中,删除语句中,查询语句及其子句中。

聚集函数:

聚集函数用于汇集记录,聚集函数就是用来处理“汇集数据”的,不要求了解详细的记录信息。 聚集函数(aggregate function) 运行在行组上,计算和返回单个值的函数。例子有:

  • 确定表中行数(或者满足某个条件或包含某个特定值的行数);
  • 获得表中某些行的和;
  • 找出表列(或所有行或某些特定的行)的最大值、最小值、平均值。

上述例子都需要汇总表中的数据,而不需要实际数据本身。
为方便这种类型的检索, SQL 给出了 5 个聚集函数:

函数 说明
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

以下说明各函数的使用。

(1)AVG()函数

  • AVG() 通过对表中行数计数并计算其列值之和,求得该列的平均值。
  • AVG() 可用来返回所有列的平均值,也可以用来返回特定列或行的平均值。
SELECT AVG(prod_price) AS avg_price
FROM Products;

此 SELECT 语句返回值 avg_price ,它包含 Products 表中所有产品的平均价格。
AVG() 也可以用来确定特定列或行的平均值。下面的例子返回特定供应商所提供产品的平均价格:

SELECT AVG(prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';

这条 SELECT 语句与前一条的不同之处在于,它包含了 WHERE 子句。此 WHERE 子句仅过滤出 vend_id 为 DLL01 的产品,因此 avg_price 中返回的
值只是该供应商产品的平均值。

?⚠警告:只用于单个列
AVG() 只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个 AVG() 函数。

?说明: NULL 值
AVG() 函数忽略列值为 NULL 的行。

(2)COUNT()函数
COUNT() 函数进行计数。可利用 COUNT() 确定表中行的数目或符合特定条件的行的数目。
COUNT() 函数有两种使用方式:

  • 使用 COUNT(*) 对表中行的数目进行计数,不管表列中包含的是空值( NULL )还是非空值。
  • 使用 COUNT(column) 对特定列中具有值的行进行计数,忽略 NULL 值。

下面的例子返回 Customers 表中顾客的总数:

##输入
SELECT COUNT(*) AS num_cust
FROM Customers;

##输出
num_cust
--------
5

在此例子中,利用 COUNT(*) 对所有行计数,不管行中各列有什么值。计数值在 num_cust 中返回。
下面的例子只对具有电子邮件地址的客户计数:

##输入
SELECT COUNT(cust_email) AS num_cust
FROM Customers;

##输出
num_cust
--------
3

这条 SELECT 语句使用 COUNT(cust_email) 对 cust_email 列中有值的行进行计数。在此例子中, cust_email 的计数为 3 (表示 5 个顾客中只有 3 个顾客有电子邮件地址)。

?说明: NULL 值
如果指定列名,则 COUNT() 函数会忽略指定列的值为空的行,但如果 COUNT() 函数中用的是星号( * ),则不忽略。

(3)MAX()函数
MAX() 返回指定列中的最大值。MAX() 要求指定列名,如下所示:

SELECT MAX(prod_price) AS max_price
FROM Products;

这里, MAX() 返回 Products 表中最贵物品的价格。

?提示:对非数值数据使用 MAX()
虽然 MAX() 一般用来找出最大的数值或日期值,但许多(并非所有) DBMS 允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。在用于文本数据时, MAX() 返回按该列排序后的最后一行。

?说明: NULL 值
MAX() 函数忽略列值为 NULL 的行。

(4)MIN()函数
MIN() 的功能正好与 MAX() 功能相反,它返回指定列的最小值。与 MAX() 一样, MIN() 要求指定列名,如下所示:

SELECT MIN(prod_price) AS min_price
FROM Products;

其中 MIN() 返回 Products 表中最便宜物品的价格。

?提示:对非数值数据使用 MIN()
虽然 MIN() 一般用来找出最小的数值或日期值,但许多(并非所有) DBMS 允许将它用来返回任意列中的最小值,包括返回文本列中的最小
值。在用于文本数据时, MIN() 返回该列排序后最前面的行。

?说明: NULL 值
MIN() 函数忽略列值为 NULL 的行。

(5)SUM()函数
SUM() 用来返回指定列值的和(总计)。下面举一个例子, OrderItems 包含订单中实际的物品,每个物品有相应的数量。可如下检索所订购物品的总数(所有 quantity 值之和):

SELECT SUM(quantity) AS items_ordered
FROM OrderItems
WHERE order_num = 20005;

函数 SUM(quantity) 返回订单中所有物品数量之和, WHERE 子句保证只统计某个物品订单中的物品。

SUM() 也可以用来合计计算值。在下面的例子中,合计每项物品的 item_price*quantity ,得出总的订单金额:

SELECT SUM(item_price*quantity) AS total_price
FROM OrderItems
WHERE order_num = 20005;

函数 SUM(item_price*quantity) 返回订单中所有物品价钱之和, WHERE 子句同样保证只统计某个物品订单中的物品。

?提示:在多个列上进行计算
如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多个列上的计算。

?说明: NULL 值
SUM() 函数忽略列值为 NULL 的行。

以上 5 个聚集函数都可以如下使用:

聚集不同值

以上 5 个聚集函数都可以如下使用:

  • 对所有行执行计算,指定 ALL 参数或不指定参数(因为 ALL 是默认行为)。
  • 只包含不同的值,指定 DISTINCT 参数。

?提示: ALL 为默认
ALL 参数不需要指定,因为它是默认行为。如果不指定 DISTINCT ,则假定为 ALL 。

?说明:不要在 Access 中使用
Microsoft Access 在聚集函数中不支持 DISTINCT ,因此下面的例子不适合于 Access 。要在 Access 得到类似的结果,需要使用子查询把 DISTINCT 数据返回到外部 SELECT COUNT(*) 语句。

下面的例子使用 AVG() 函数返回特定供应商提供的产品的平均价格。它与上面的 SELECT 语句相同,但使用了 DISTINCT 参数,因此平均值只考虑各个不同的价格:

SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';

?警告: DISTINCT 不能用于 COUNT(*)
如果指定列名,则 DISTINCT 只能用于 COUNT() 。 DISTINCT 不能用于 COUNT(*) 。类似地, DISTINCT 必须使用列名,不能用于计算或表达
式。

?提示:将 DISTINCT 用于 MIN() 和 MAX()
虽然 DISTINCT 从技术上可用于 MIN() 和 MAX() ,但这样做实际上没有价值。一个列中的最小值和最大值不管是否只考虑不同值,结果都是相同的。

?说明:其他聚集参数
除了这里介绍的 DISTINCT 和 ALL 参数,有的 DBMS 还支持其他参数,如支持对查询结果的子集进行计算的 TOP 和 TOP PERCENT 。为了解具体的 DBMS 支持哪些参数,请参阅相应的文档。

组合聚集函数

目前为止的所有聚集函数例子都只涉及单个函数。但实际上, SELECT 语句可根据需要包含多个聚集函数。请看下面的例子:

##输入 ▼
SELECT COUNT(*) AS num_items,
MIN(prod_price) AS price_min,
MAX(prod_price) AS price_max,
AVG(prod_price) AS price_avg
FROM Products;
##输出 ▼
num_items     price_min      price_max       p rice_avg
---------- --------------- --------------- ---------------
9              3.4900         11.9900        6.823333

这里用单条 SELECT 语句执行了 4 个聚集计算,返回 4 个值( Products 表中物品的数目,产品价格的最高值、最低值以及平均值)。

?警告:取别名
在指定别名以包含某个聚集函数的结果时,不应该使用表中实际的列名。虽然这样做也算合法,但许多 SQL 实现不支持,可能会产生模糊的错误消息。

聚集函数用来汇总数据。 SQL 支持 5 个聚集函数,可以用多种方法使用它们,返回所需的结果。这些函数很高效,它们返回结果一般比你在自己的客户端应用程序中计算要快得多。

函数带来的问题
与几乎所有 DBMS 都等同地支持 SQL 语句(如 SELECT )不同,每一个 DBMS 都有特定的函数。事实上,只有少数几个函数被所有主要的 DBMS等同地支持。虽然所有类型的函数一般都可以在每个 DBMS 中使用,但各个函数的名称和语法可能极其不同。为了说明可能存在的问题,下表 列出了 3 个常用的函数及其在各个 DBMS 中的语法:

函数 语法
提取字符串的组成部分 Access 使用 MID() ; DB2 、 Oracle 、 PostgreSQL 和 SQLite 使用 SUBSTR() ; MySQL 和 SQL Server 使用 SUBSTRING()
数据类型转换 Access 和 Oracle 使用多个函数,每种类型的转换有一个函数; DB2 和 PostgreSQL 使用 CAST() ; MariaDB 、 MySQL 和 SQL Server 使用CONVERT()
取当前日期 Access 使用 NOW() ; DB2 和 PostgreSQL 使用 CURRENT_DATE ; MariaDB 和 MySQL 使用 CURDATE() ; Oracle 使用 SYSDATE ; SQL Server使用 GETDATE() ; SQLite 使用 DATE()

可以看到,与 SQL 语句不一样, SQL 函数不是可移植( 可移植:portable 所编写的代码可以在多个系统上运行)的。这表示为特定 SQL 实现编写的代码在其他实现中可能不正常。

为了代码的可移植,许多 SQL 程序员不赞成使用特定于实现的功能。虽然这样做很有好处,但有的时候并不利于应用程序的性能。如果不使用这些函数,编写某些应用程序代码会很艰难。必须利用其他方法来实现 DBMS 可以非常有效完成的工作。
大多数 SQL 实现支持以下类型的函数。

  • 用于处理文本字符串(如删除或填充值,转换值为大写或小写)的文本函数。
  • 用于在数值数据上进行算术操作(如返回绝对值,进行代数运算)的数值函数。
  • 用于处理日期和时间值并从这些值中提取特定成分(如返回两个日期之差,检查日期有效性)的日期和时间函数。
  • 返回 DBMS 正使用的特殊信息(如返回用户登录信息)的系统函数。

函数用作 SELECT 语句的列表成分,但函数的作用不仅于此。它还可以作为 SELECT 语句的其他成分,如在 WHERE 子句中使
用,在其他 SQL 语句中使用等,后面会做更多的介绍。

文本处理函数:

下面是一个例子,使用的是 UPPER() 函数:

SELECT vend_name, UPPER(vend_name) AS vend_name_upcase
FROM Vendors
ORDER BY vend_name;

UPPER() 将文本转换为大写,因此本例子中每个供应商都列出两次,第一次为Vendors 表中存储的值,第二次作为列 vend_name_upcase 转换为大写。

下表列出了一些常用的文本处理函数。

函数 说明
LEFT() (或使用子字符串函数) 返回字符串左边的字符
LENGTH() (也使用 DATALENGTH() 或 LEN() ) 返回字符串的长度
LOWER() ( Access 使用 LCASE() ) 将字符串转换为小写
LTRIM() 去掉字符串左边的空格
RIGHT() (或使用子字符串函数) 返回字符串右边的字符
RTRIM() 去掉字符串右边的空格
SOUNDEX() 返回字符串的 SOUNDEX 值
UPPER() ( Access 使用 UCASE() ) 将字符串转换为大写

表中的 SOUNDEX 需要做进一步的解释。 SOUNDEX 是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。 SOUNDEX 考虑了类似的发音字符和音节,使得能对字符串进行发音比较而不是字母比较。虽然 SOUNDEX 不是 SQL 概念,但多数 DBMS 都提供对 SOUNDEX 的支持。

?说明: SOUNDEX 支持

  • Microsoft Access 和 PostgreSQL 不支持 SOUNDEX() ,因此以下的例子不适用于这些 DBMS 。
  • 另外,如果在创建 SQLite 时使用了 SQLITE_SOUNDEX 编译时选项,那么 SOUNDEX() 在 SQLite 中就可用。因为 SQLITE_SOUNDEX 不是默认的编译时选项,所以多数 SQLite 实现不支持 SOUNDEX() 。

下面给出一个使用 SOUNDEX() 函数的例子。 Customers 表中有一个顾客 Kids Place ,其联系名为 Michelle Green 。但如果这是错误的输入,此联系名实际上应该是 Michael Green ,该怎么办呢?显然,按正确的联系名搜索不会返回数据,如下所示:

##输入 ▼
SELECT cust_name, cust_contact
FROM Customers
WHERE cust_contact = 'Michael Green';
##输出 ▼
cust_name   cust_contact
----------------- ---------------------

现在试一下使用 SOUNDEX() 函数进行搜索,它匹配所有发音类似于 Michael Green 的联系名:

##输入 ▼
SELECT cust_name, cust_contact
FROM Customers
WHERE SOUNDEX(cust_contact) = SOUNDEX('Michael Green');
##输出 ▼
cust_name    cust_contact
-------------------- -------------------------
Kids Place   Michelle Green

在这个例子中, WHERE 子句使用 SOUNDEX() 函数把 cust_contact 列值和搜索字符串转换为它们的 SOUNDEX 值。因为 Michael Green 和 MichelleGreen 发音相似,所以它们的 SOUNDEX 值匹配,因此 WHERE 子句正确地过滤出了所需的数据。

日期和时间处理函数:

日期和时间采用相应的数据类型存储在表中,每种 DBMS 都有自己的特殊形式。日期和时间值以特殊的格式存储,以便能快速和有效地排序或过滤,并且节省物理存储空间。

应用程序一般不使用日期和时间的存储格式,因此日期和时间函数总是用来读取、统计和处理这些值。由于这个原因,日期和时间函数在 SQL中具有重要的作用。遗憾的是,它们很不一致,可移植性最差。

举个简单的例子,来说明日期处理函数的用法。 Orders 表中包含的订单都带有订单日期。为在 SQL Server /Access 中检索 2012 年的所有订单,可如下进行:

##SQL Server:
SELECT order_num
FROM Orders
WHERE DATEPART(yy, order_date) = 2012;

## Access:
SELECT order_num
FROM Orders
WHERE DATEPART('yyyy', order_date) = 2012;

## PostgreSQL
SELECT order_num
FROM Orders
WHERE DATE_PART('year', order_date) = 2012;

##Oracle 没有 DATEPART() 函数,可使用其他方法
SELECT order_num
FROM Orders
WHERE to_number(to_char(order_date, 'YYYY')) = 2012;
** to_char() 函数用来提取日期的成分, to_number() 用来将提取出的成分转换为数值
或:
SELECT order_num
FROM Orders
WHERE order_date BETWEEN to_date('01-01-2012')
AND to_date('12-31-2012');
** to_date() 函数用来将两个字符串转换为日期。

##MySQL / MariaDB ,没有 DATEPART() 
SELECT order_num
FROM Orders
WHERE YEAR(order_date) = 2012;

##在 SQLite 中有个小技巧:
SELECT order_num
FROM Orders
WHERE strftime('%Y', order_date) = 2012;

这个例子( SQL Server 和 Sybase 版本以及 Access 版本)使用了 DATEPART() 函数,顾名思义,此函数返回日期的某一部分。 DATEPART() 函数有两个参数,它们分别是返回的成分和从中返回成分的日期。在此例子中, DATEPART() 只从 order_date 列中返回年份。通过与 2012 比较, WHERE 子句只过滤出此年份的订单。

DBMS 提供的功能远不止简单的日期成分提取。大多数 DBMS 具有比较日期、执行基于日期的运算、选择日期格式等的函数。但是,可以看到,不同 DBMS 的日期 - 时间处理函数可能不同。关于具体 DBMS 支持的日期 - 时间处理函数,请参阅相应的文档。

数值处理函数:

数值处理函数仅处理数值数据。这些函数一般主要用于代数、三角或几何运算,因此不像字符串或日期 - 时间处理函数使用那么频繁。
具有讽刺意味的是,在主要 DBMS 的函数中,数值函数是最一致、最统一的函数。下表列出一些常用的数值处理函数。

函数 说明
ABS() 返回一个数的绝对值
COS() 返回一个角度的余弦
EXP() 返回一个数的指数值
PI() 返回圆周率
SIN() 返回一个角度的正弦
SQRT() 返回一个数的平方根
TAN() 返回一个角度的正切

关于具体 DBMS 所支持的算术处理函数,请参阅相应的文档。
虽然这些函数在格式化、处理和过滤数据中非常有用,但它们在各种 SQL 实现中很不一致( SQLServer 和 Oracle 之间的差异说明了这一点)。

你可能感兴趣的:(SQL)