LeetCode数据库篇|有时间就更新

Posted Eric%258436

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode数据库篇|有时间就更新相关的知识,希望对你有一定的参考价值。

** 如有错误,感谢指正**

如有错误,感谢指正,请私信博主,有辛苦红包,拜“一字之师”。

请根据目录寻找自己需要的段落

导语:本博客为个人整理Java学习记录帖,如有错误,感谢指正。系统学习,欢迎持续关注,后续陆陆续续更新~
Java 交流qq群 383245788。群内有一些资源和大佬,欢迎进来交流。

本文旨在学习交流,个人LeetCode刷题学习心得

PS: leetcode测试数据一般都不大,要从原理的角度去理解和估摸时间!

1.组合两个表

原LeetCode 题号175 简单
题目描述
表1: Person

列名类型
PersonIdint
FirstNamevarchar
LastNamevarchar

PersonId 是上表主键

列名类型
AddressIdint
PersonIdint
Cityvarchar
Statevarchar

AddressId 是上表主键

编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:
FirstName, LastName, City, State

select FirstName, LastName, City, State 
from Person left join Address 
on Person.PersonId = Address.PersonId;
  • from子句中on条件主要用来连接表,其他不属于连接表的条件可以使用where子句来指定; join连接分为三种,1内连接,2外连接,3交叉连接; 1:inner join ,默认,所以可以省略inner关键字 2:left outer join ,左外连接,结果表中除了匹配行外,还包括左表有而右表中不匹配的行,对于这样的行,右表选择列置为null right outer join ,右外连接,结果表中除了匹配行外,还包括右表有而左表中不匹配的行,对于这样的行,左表选择列置为null natural join,自然连接,分为natural left outer join和natural right outer join,语义定义与inner join相同 3:cross join,交叉连接,实际上就是将两个表进行笛卡尔积运算,结果表的行数等于两表行数之积
  • 需要注意的是:on与where的区别
    数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。 在使用left jion时,on和where条件的区别如下:
    1、on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
    2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。
  • 为啥不用Where? 因为where的实质就是根据你给的条件(personID相等),选取两表的公共部分。但是,因为PERSON表不是所有人都有地址信息的,但是ADDRESS表只显示有地址信息的人,这样选取出来的就是有地址信息的人,漏掉了没有地址信息的人。所以大家注意,where的本质就是过滤。
  • 为什么不用别名?使用别名是为了区分两个表中的相同名字的字段,这两个表没用相同名字字段不需要用别名区分。而且使用别名会增加运行时间。
  • 为啥是left join而不是join或者 right join? left在左边 表示前一个表是一个基准表。基准表的所有字段无论是否记录为null都要显示在联合表中。right同理。因为我们是对右边表做限制,因此用left join。另外left join其实是left outer join 属于外连接表之间有“等级” 。inner join:两表值都存在。outer join:附表中值可能存在null的情况。outer join 包括 left join , right join 和full join ,看情况来选择需要的外连接,一般不写outer 采用简写。
    ①A inner join B:取交集
    ②A left join B:取A全部,B没有对应的值,则为null
    ③A right join B:取B全部,A没有对应的值,则为null
    ④A full outer join B:取并集,彼此没有对应的值为null
    上述4种的对应条件,在on后填写。

2. 超过经理收入的员工

原LeetCode 题号181 简单
题目描述
表:Employee

Column NameType
idint
namevarchar
salaryint
managerIdint

编写一个SQL查询来查找收入比经理高的员工。
以 任意顺序 返回结果表。
查询结果格式如下所示。
输入:
Employee 表:

idnamesalarymanagerId
1Joe700003
2Henry800004
3Sam60000Null
4Max90000Null

输出:

Employee
Joe

解释: Joe 是唯一挣得比经理多的雇员。

// 博主 题解 
select e.name as 'Employee'
from Employee e 
where salary > (select salary from Employee where Id = e.managerId)
// 自链接  用时较短,相较于我的节省近70%的时间。 92语法等值连接(等价于99语法的INNER JOIIN) 但是就是很快。是我目前见过最快的写法。大概原因是leetcode表里面的数据太少了,如果是百万,千万条估计就只能rm -rf了
select e1.Name as Employee
from employee e1, employee e2
where e1.ManagerId= e2.Id
and e1.Salary > e2.Salary
// leetcode官方解1 这个也比我那个快,节省60%左右。提醒大家,尽量少的去创建新表,对比查询,最慢了
SELECT
    a.Name AS 'Employee'
FROM
    Employee AS a,
    Employee AS b
WHERE
    a.ManagerId = b.Id
        AND a.Salary > b.Salary
;
// 题解2 这个也不是很快,跟题解1 差不多,但要比1快一点点
SELECT
     a.NAME AS Employee
FROM Employee AS a JOIN Employee AS b
     ON a.ManagerId = b.Id
     AND a.Salary > b.Salary
;
  • 连接查询比子查询要快的。但是也不一定,比如子表数据多,或者索引没命中。而且也要看数据量的,这个连接查询有笛卡尔积,子查询有重复查询,都有可能比对方慢,本题的原因就是可能就是数据量少。

3.查找重复的电子邮箱

原LeetCode 题号182 简单
题目:
编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
示例:

IdEmail
1a@b.com
2c@d.com
3a@b.com

根据以上输入,你的查询应返回以下结果:

Email
a@b.com

说明:所有电子邮箱都是小写字母。

// 答主题解 自连接
select distinct e1.Email from Person as e1,Person as e2 where e1.Email = e2.Email and e1.Id != e2.Id;

此题比较简单,解法挺多,大同小异。基本思路都是 查询+去重

// 解法1 having + 聚合函数
select email from person group by email having count(email)>1

// 解法2 子表查询
select email from (select count(1) as t,email from person group by email)r  where r.t>1;

// 解法3 自连接
select distinct(p1.Email) from Person p1  
join Person  p2 on p1.Email = p2.Email AND p1.Id!=p2.Id

// 解法4 子表查询
select email from (select count(email)as m,email from Person group by email) as a where a.m>=2 

4.第二高的薪水

原LeetCode 题号176 中等
题干
编写一个 SQL 查询,获取并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null 。

输入:
Employee 表:

idsalary
1100
2200
3300

输出:

SecondHighestSalary
200

输入:
Employee 表:

idsalary
1100

输出:

SecondHighestSalary
null
select (select distinct salary from Employee Order By salary desc limit 1 ,1) as SecondHighestSalary;

//原本我写的也是下面这个,但是遇到null 输出是空,但是写成上面那个就会返回null。也不是很理解其中的语法与道理。
// leetcode官方题解 的大概意思是 把内查询当临时表,可能做临时表时,这个有什么操作,变成null了
// 如果有大佬了解,请评论解答一下
select distinct salary from Employee order by salary desc limit 1,1 

// offset版本
SELECT DISTINCT
    Salary AS SecondHighestSalary
FROM
    Employee
ORDER BY Salary DESC
LIMIT 1 OFFSET 1
// 思路一
select ifNull((
select distinct Salary
from Employee
order by Salary desc limit 1,1),null) as SecondHighestSalary

// 思路二
SELECT max(Salary) SecondHighestSalary
 FROM Employee  
where Salary != (select max(Salary) from Employee ); 

以上是关于LeetCode数据库篇|有时间就更新的主要内容,如果未能解决你的问题,请参考以下文章

leetcode中那些奇妙的解法(持续更新)

LeetCode算法题-Move Zeroes(Java实现-三种解法)

LeetCode算法题-Valid Perfect Square(Java实现-四种解法)

200道大数据面试常考Leetcode算法题--数组篇02(python带代码解析)

LeetCode算法题-Power of Four(Java实现-六种解法)

LeetCode算法题-Find the Difference(Java实现-五种解法)