刷完了简单难度的数据库题目,对sql中的一些语法特性有了简单的了解,算是学会了挺多思路,还有很多的小技巧
总之就是感觉使用sql能完成的任务越来越多了,能解决的业务场景也也越来越复杂了。有许多之前不得不拿到程序中才能处理的数据使用简单的sql就能够达成,当事人就很有成就感。
所以刷题整理这个过程还会持续下去,从这篇博文开始,就是中等难度的了,由于题目较长或者题解较简单稍微复杂。所以为了避免每篇博文过于冗长,暂定是5-6道题一篇。会挑选博主觉得比较有意义的题目(根据博主不算高的水平)
往期的题解会放在最后,欢迎阅览、交流、讨论。
题目需要我们统计当选者,即获得投票最高的人。
题目保证了其中最高票数的人仅有一人
于是我们可以先试用子查询查询出获得票数最多的那个人的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年的投资,但是有效投资需要满足两个条件:
所以我们使用子查询分别筛选出满足这两个条件的子集,在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
)
;
题目链接
这道题在简单题目中有一道兄弟题目:直线上的最近距离
在这道题中,点的分布从一条直线变成了一个平面。本质上并没有变化,只不过是关键字从一个变成了两个,距离的计算公式发生了变化。
我们使用自联结将每个节点同非自己的节点相联结,并计算出其间距离,按照距离排序取最小即可。
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
;
题目链接
这道题需要我们找出所有树的节点的类型,其可能是根、叶子、节点。
一个朴素的想法是使用自联结将这个树结构联结起来,然后根据id进行分组,再从联结表的内容来判断其内容。
不难发现,是那种节点有如下特性:
所以我们分好组,使用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
;
有一点需要注意的是,申请添加好友的双方都会各自有一位好友,所以一个人的好友数是其在请求放和接收方出现次数的总和。
所以我们先将所有在申请方和接收方的用户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
;