【LeetCode数据库】 题目总结——经典题目题解与分析(一)--简单难度

前言

这段时间,刷了LeetCode的数据库题目,挺有感触的。在刷这些题之前,我只写过一般的增删改查,尤其是查询操作,使用的也不是很灵活,只知道最基本的用法。

去刷了题目之后真的学到了很多不论是新的知识点还是一些组合用法,总之对数据库操作尤其是dql的使用更加熟练了。感谢其他leetcoder对各种知识点和解题套路的分享,学会这些小操作后,写sql头不疼了,腰不酸了,睡得着了,吃饭也更香了。

根据这些题,我总结了一些常用的知识点、小技巧以及部分有代表性的题解。

这篇文章就来分享一些有价值的题解。题目有些多,这篇先展示其中八题的题解。

剩下的在这里

  • 题目总结——经典题目题解与分析(二)–简单
  • 题目总结——经典题目题解与分析(三)–简单

超过经理收入的员工

题目链接
在这里插入图片描述
真的很经典的一道题了,按照题号开始刷题的话这是第一个碰上的不好写的题目。

主要难点在于对同一个表中某些行的特定字段进行比较。由于SQL不能像一般编程语言那样自由的对表中的数据进行“遍历”
对于这样的题,特点就是比较不同行的同一列,而非同一行的不同列,不便于直接处理。

解决它的方法就是进行自联结,在该表的笛卡尔积中我们能找到所有行与行的组合,再使用条件筛选出其中需要比较的行,剩下的问题就转化成了同一行的不同列进行比较。

select
    e1.name as employee
from 
    employee e1
    left join employee e2 on e1.managerId = e2.id
where
    e1.salary > e2.salary;

连续空余座位

题目链接
在这里插入图片描述
这个题目仍旧是比较一张表中同一字段的不同行。

直接使用自联结,将那些需要比较的行的组合(相邻的两行)筛选下来,进行同一行不同字段的比较。

select
    c1.seat_id
from 
    cinema c1
    left join cinema c2 on c1.seat_id = c2.seat_id - 1
    left join cinema c3 on c1.seat_id = c3.seat_id + 1
where
    c1.free = 1
    and
    (
        c2.free = 1
        or 
        c3.free = 1
    )
;

上升的温度

题目链接
在这里插入图片描述
同上一题相似,这一题也是对一张表中的不同行的同一列进行比较。

我们直接使用上面的套路,进行自联结,筛选掉不合适的组合(不是差一天的关系)

剩下的就是同一行不同列的比较了。

SELECT
    a.id as id
FROM 
    weather a
    join weather b
    on datediff(a.recorddate,b.recorddate) = 1
    and a.temperature > b.temperature
;

删除重复的电子邮箱

题目链接
在这里插入图片描述
一种不太常见的题型——使用DML对表单数据进行删除处理

这道理另一个不好处理的问题在于,如果使用子查询将所有重复的第一个id查询出来再使用where条件删除剩余不重复的元素会因为操作表单和查询表单相同而报错

一种可行的处理办法是套一层娃,将查询出来的表单再嵌套一层查询,用一个临时的表单代替待操作的表单。

delete from
    person
where 
    id not in(
        select 
            id
        from(
            select 
                min(id) as id
            from 
                person 
            group by
                email
        )t
    )

还有一种更简洁的方法,是使用多表删除的操作。多表删除是5.0版本以后新增的操作,他允许我们进行多表联结,并将进行删除操作表的出现在联结表单中的行删除。

delete
    p1
from 
    person p1,
    person p2
where   
    p1.email = p2.email
    and
    p1.id > p2.id
;

游戏玩法分析

题目链接
在这里插入图片描述
这个题目需要我们首先处理玩家第一次登录的时间,之后再找出玩家在这个登录时间使用的设备

难点在于匹配登录设备时,主键是玩家的id和他第一次登录的时间,这个需要我们是用多个字段同时使用in来进行匹配:

select
    player_id,
    device_id
from 
    activity
where
    (player_id,event_date) in(
        select  
            player_id,
            min(event_date)
        from
            activity
        group by
            player_id
    );

好友申请I:总体通过率

题目链接
在这里插入图片描述
在这里插入图片描述
这个题目需要我们从两个表单中查询出一个结果值并进行运算,另外,还需要在各自的表单中进行去重。

有一种去重方式是进行分组,但是由于这道题需要使用到聚合函数对整个表单的结果进行统计,因此这道题不适合使用分组去重。

另外一种去重方式就是使用关键字distinct,分别根据各自表中的两个关键字进行去重。

select
    round(ifnull(
        (select count(distinct requester_id,accepter_id) from request_accepted)/
        (select count(distinct sender_id,send_to_id) from friend_request)
        ,0),2) as accept_rate;

销售员

题目链接
在这里插入图片描述

在这里插入图片描述

题目需要我们找出所有没有向red公司出售过商品的销售员,正着做不好搞,我们就反着来。

先查找出所有项red公司出售过商品的销售员,再从所有的销售员中除去这些销售员即可。

SELECT 
    s.name as name
FROM
    salesperson s
WHERE
    s.sales_id NOT IN (
        SELECT sales_id
        FROM orders
        WHERE
        orders.com_id in (
            select com_id
            from company
            where name = 'RED'
        )
    );

直线上的最近距离

题目链接
在这里插入图片描述
又是一道同一字段不同行之间的比较

我们使用自联结,筛选出所有不同行的组合。

在这之后,计算差的绝对值就非常容易了,我们直接输出最小的那个就行。

输出最小的那个可以采用排序的方法,或者使用聚合函数min

SELECT 
    ABS(x1.x - x2.x) as shortest
FROM 
    point x1
    JOIN point x2 
    on x1.x != x2.x
ORDER BY
ABS(x1.x - x2.x) 
LIMIT 0,1;
SELECT 
    min(ABS(x1.x - x2.x)) as shortest
FROM 
    point x1
    JOIN point x2 
    on x1.x != x2.x
;

猜你喜欢

转载自blog.csdn.net/wayne_lee_lwc/article/details/108132358