2018-10-11
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 |
+------------------------+
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
-- 不行的代码: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");
-- 无参调用
select myselect3();
-- 传参调用
select myselect5("python");
select * from class where id=myselect5("python");
聚集函数用于汇集记录,聚集函数就是用来处理“汇集数据”的,不要求了解详细的记录信息。 聚集函数(aggregate function) 运行在行组上,计算和返回单个值的函数。例子有:
上述例子都需要汇总表中的数据,而不需要实际数据本身。
为方便这种类型的检索, SQL 给出了 5 个聚集函数:
函数 | 说明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行数 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
以下说明各函数的使用。
(1)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() 函数有两种使用方式:
下面的例子返回 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 。
?说明:不要在 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 实现支持以下类型的函数。
函数用作 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 之间的差异说明了这一点)。