1. 题目1
表1:Person,PersonId是该表主键
| 列名 | 类型 |
|---|
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
表2:Address,AddressId是该表主键
| 列名 | 类型 |
|---|
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
编写一个SQL查询,满足条件:无论person是否有地址信息,都要基于上述两表提供person的以下信息:
FirstName,Lastame,City,State
解答:
select p.FirstName, p.Lastame,a.City,a.State
from Person p left join Address a
on p.PersonId = a.PersonId;
解析1:
Address表中的PersonId是Person表外关键字。
无论person是否有地址细腻,都要提供person的在Person表中的两个字段信息。所以选择外连接中outer join中的
左连接left (outer) join或右连接right (outer) join。
left outer join左外连接:结果表中除了匹配行外,还包括左表有而右表中不匹配的行。
解析2:
SQL语句执行顺序:
From <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>
数据库再连接两张表或多张表来返回记录时,都会生成一个中间的临时表,然后再将这张临时表返回给用户。
ON条件执行后再生成临时表,不管ON中的条件是否为真,都会返回坐表的所有记录。
WHERE条件是在临时表生成之后,在进行筛选,只筛选条件为真的记录。
解析3:where语句的结果
SELECT *
FROM person p, address a
WHERE p.`PersonId` = a.`PersonId`;
只会筛选满足where条件的记录:p.`PersonId` = a.`PersonId`:发现没有满足条件的,所以没有查询到记录:

2.题目2
表1:Employee, id是该表主键
题目:
编写一个SQL查询,获取Employee表中第二高的薪水(Salary)
如果不存在第二高的薪水,那么查询返回null。
例如:查询结果
解析:
倒序排序DESC
LIMIT取第二行记录,且只取一行:limit 1,1
不存在第二高的薪水,那么查询返回null
知识点1:limit 1 offset 1
MySQL是从第0条数据开始读的。
limit y 分句表示: 子句表示查询结果返回前y条数据
limit x,y 分句表示:跳过x条数据,读取y行数据
limit y offset x 分句表示:跳过x条数据,读取y行数据
例子:分页获取数据
# 第一页:从第0个数据开始,获取20条数据
select * from testtable limit 0, 20;
select * from testtable limit 20 offset 0;
# 第二页:从第20个数据开始,获取20条数据
select * from testtable limit 20,20;
select * from testtable limit 20 offset 20;
# 第三页:从第40个数据开始,获取20条数据
select * from testtable limit 40,20;
select * from testtable limit 20 offset 40;
知识点2:select distinct
注意limit分页语句在最后执行,所以要先进行一个distinct去重。因为需要考虑到这些情况:
id salary
1 100
2 100
此时如果不用select distinct的话,就会把第二行的 100 取出来,但是表中没有第二高的salary。
知识点3:select null 返回null
如果表中只有一行数据,或者所有行数据都是一样的:
id salary
1 100
2 100
3 100
此时是没有第二高的薪水的,所以查询结果应该返回null。
知识点4:ifnull(a,b)函数
如果a不是空,返回a;如果a是空,返回b。
思路A:
select distinct salary
from employee
order by salary desc;
该语句可以保证同样的数据将会去重的效果,得到结果:

思路B:
select distinct salary
from employee
order by salary desc
limit 1 offset 1;
此时因为去重后之后只有一条记录,所以取第二行数据是不存在的,没有数据也不返回null:

思路C1:
SELECT (
SELECT DISTINCT salary
FROM employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1
) AS SecondHighestSalary;
此时将刚才排序后的表作为临时表,运用select null会返回null,来完成题目:

解法2:ifnull(a,b)函数
如果a不是空,返回a;如果a是空,返回b。
select ifnull(
(select distinct salary
from employee
order by salary desc
limit 1 offset 1), null) as SecondHighestSalary;
小结:方法一select null返回null的查询效率要高效一些。