【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度

刷完了简单难度的数据库题目,对sql中的一些语法特性有了简单的了解,算是学会了挺多思路,还有很多的小技巧

总之就是感觉使用sql能完成的任务越来越多了,能解决的业务场景也也越来越复杂了。有许多之前不得不拿到程序中才能处理的数据使用简单的sql就能够达成,当事人就很有成就感。

所以刷题整理这个过程还会持续下去,从这篇博文开始,就是中等难度的了,由于题目较长或者题解较简单稍微复杂。所以为了避免每篇博文过于冗长,暂定是5-6道题一篇。会挑选博主觉得比较有意义的题目(根据博主不算高的水平)

往期的题解会放在最后,欢迎阅览、交流、讨论。


当选者

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第1张图片【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第2张图片
这道题比较简单,可以算作热身题

题目需要我们统计当选者,即获得投票最高的人。

题目保证了其中最高票数的人仅有一人

于是我们可以先试用子查询查询出获得票数最多的那个人的id

然后再从参选者当中选出那个人的名字

select
    name
from 
    candidate
where 
    id in (
        select(
        select
            candidateid
        from 
            vote
        group by
            candidateid
        order by    
            count(id) desc
        limit 0,1)
    )

2016年的投资

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第3张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第4张图片
这道题需要我们统计2016年的投资,但是有效投资需要满足两个条件:

  • 2015年的投资数必须有同年相同资金的投资
  • 该笔投资的地点(经纬度)必须独一无二

所以我们使用子查询分别筛选出满足这两个条件的子集,在where条件中使用in语句进行筛选两个集合的交集即可。

判断15年有没有投资数量一样的投资,我们可以使用自联结,条件就是投资金额一样,这样一来,所有没有相同数目的投资都被筛选掉了,剩下的都是具有相同额度的投资。需要注意的就是一条记录不要联结自己,自己同自己的投资金额一定是相同的,联结记录自己没有意义。

筛选经纬度独一无二的记录也不难办到,我们可以借鉴上面的经验,使用自联结。但是那样我们筛选出来的具有重复经纬度的记录。那我们不妨将表格按照经纬度两个关键字进行分组,之后所有组中元素数量为1的组就是独一无二的。

select
    round(sum(tiv_2016),2) as tiv_2016
from 
    insurance
where 
    pid in (
        select 
            distinct i1.pid
        from 
            insurance i1
            join insurance i2 on i1.tiv_2015 = i2.tiv_2015 and i1.pid != i2.pid
    )
    and pid in(
        select  
            pid
        from 
            insurance
        group by
            lat,lon
        having 
            count(pid) = 1
    )
;

平面上的最近距离

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第5张图片
这道题在简单题目中有一道兄弟题目:直线上的最近距离

在这道题中,点的分布从一条直线变成了一个平面。本质上并没有变化,只不过是关键字从一个变成了两个,距离的计算公式发生了变化。

我们使用自联结将每个节点同非自己的节点相联结,并计算出其间距离,按照距离排序取最小即可。

select
    round(sqrt(pow(p1.x - p2.x,2) + pow(p1.y - p2.y,2)),2) as shortest
from 
    point_2d p1
    join point_2d p2 on p1.x != p2.x or p1.y != p2.y
order by
    pow(p1.x - p2.x,2) + pow(p1.y - p2.y,2) 
limit 0,1
;

树节点

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第6张图片【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第7张图片
这道题需要我们找出所有树的节点的类型,其可能是根、叶子、节点。

一个朴素的想法是使用自联结将这个树结构联结起来,然后根据id进行分组,再从联结表的内容来判断其内容。

不难发现,是那种节点有如下特性:

  • 根没有父节点,父节点p_id是null
  • 节点具有子节点,对子节点的计数值应该大于0
  • 剩下的都是叶子节点

所以我们分好组,使用case-when语句判断这些情况就可以啦。

select
    distinct t1.id,
    (
        case
            when t1.p_id is null then 'Root'
            when count(t2.p_id) > 0 then 'Inner'
            else 'Leaf'
        end
    ) Type
from 
    tree t1
    left join tree t2 on t1.id = t2.p_id
group by
    t1.id
;

好友申请II:谁拥有最多的好友

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(五)--中等难度_第8张图片
这道题,需要我们统计哪个用户拥有最多的好友。

有一点需要注意的是,申请添加好友的双方都会各自有一位好友,所以一个人的好友数是其在请求放和接收方出现次数的总和。

所以我们先将所有在申请方和接收方的用户id给查询出来,再按照id进行分组,最后输出那个最高的人就行了。

拼接申请方和接收方的时候可以使用到union,但是需要注意的是,union会对数据进行去重,这是我们不希望的,所以在这道题里面,要用union all!!

select 
    id,
    count(*) as num
from (
    select
        requester_id id
    from 
        request_accepted

    union all

    select  
        accepter_id id
    from 
        request_accepted
) tab
group by
    id
order by 
    count(*) desc
limit 0,1
;

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

你可能感兴趣的:(#,LeetCode数据库,数据库,数据分析,mysql)