MySQL习题

379 阅读4分钟

1. 题目1

表1:Person,PersonId是该表主键

列名类型
PersonIdint
FirstNamevarchar
LastNamevarchar

表2:Address,AddressId是该表主键

列名类型
AddressIdint
PersonIdint
Cityvarchar
Statevarchar
编写一个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) joinleft outer join左外连接:结果表中除了匹配行外,还包括左表有而右表中不匹配的行。
    
解析2SQL语句执行顺序:
    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条件是在临时表生成之后,在进行筛选,只筛选条件为真的记录。
    
解析3where语句的结果
    SELECT * 
    FROM person p, address a
    WHERE p.`PersonId` = a.`PersonId`;
	只会筛选满足where条件的记录:p.`PersonId` = a.`PersonId`:发现没有满足条件的,所以没有查询到记录:

2.题目2

表1:Employee, id是该表主键

列名类名
idsaraly
1100
2200
3300
题目:
	编写一个SQL查询,获取Employee表中第二高的薪水(Salary)
	如果不存在第二高的薪水,那么查询返回null。
	例如:查询结果
SecondHighestSalary
200
解析:
	倒序排序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;
知识点2select distinct 
	
    注意limit分页语句在最后执行,所以要先进行一个distinct去重。因为需要考虑到这些情况:
    id	salary
    1	100
    2	100
    此时如果不用select distinct的话,就会把第二行的 100 取出来,但是表中没有第二高的salary。
    
知识点3select 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的查询效率要高效一些。