【LeetCode数据库】 题目总结——经典题目题解与分析(三)

前言

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

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

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

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

剩下的在这里

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

学生们参加各科测试的次数

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第1张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第2张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第3张图片
这道题首先应该看出,结果是学生表和科目表的可卡尔积。

所以我们应该首先将学生和科目两个表直接联结形成笛卡尔积。

然后我们将这个表当做新的表,主键为学生id和科目组成的联合主键,再去联结考试表。

最后,根据联合主键进行分组和排序,统计出每个同学每个科目的参与次数。

SELECT
    s.student_id,
    s.student_name,
    sb.subject_name,
    COUNT(e.student_id) AS attended_exams
FROM 
    Students s
    join Subjects sb
    LEFT JOIN Examinations e 
    on e.subject_name = sb.subject_name and e.student_id = s.student_id
GROUP BY
    s.student_id,sb.subject_name
ORDER BY
    s.student_id,sb.subject_name;

不同国家的天气类型

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第4张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第5张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第6张图片
首先,国家表和天气表是关联关系,我们需要先将他们两个联结起来。

接着,需要筛选出所有11月份的天气信息

然后,对表按照国家进行分组

最后,根据每个国家的平均气温来确定该国家的气候类型。这里涉及到分支判断,推荐使用case-when来解决问题

SELECT 
    c.country_name,
    CASE
        WHEN AVG(w.weather_state) <= 15 THEN 'Cold'
        WHEN AVG(w.weather_state) >= 25 THEN 'Hot'
        ELSE 'Warm'
    END AS weather_type
FROM 
    Countries c 
    JOIN Weather w ON c.country_id = w.country_id
WHERE 
    w.day LIKE '2019-11%'
GROUP BY c.country_name;
;

求团队人数

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第7张图片
这个题目需要我们统计每个员工所在团队的规模。

那我们就先使用子查询查询出所有团队的规模,记作表t

接着根据团队id联结两张表t和employee,输出其中员工id和团队规模两列即可。

select
    employee_id,
    team_size
from 
    employee e
    join
    (
        select 
        team_id,
        count(*) as team_size
        from employee
        group by team_id
    ) t on e.team_id = t.team_id
;

广告效果

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第8张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第9张图片
这个题目,需要我们统计每个广告的点击操作数占点击和观看操作的比率

首先,我们需要根据广告id进行分组。

接着,我们在统计的时候可以使用聚合函数配合case-when来完成筛选

最后不要忘记对答案进行保留两位小数和null处理

select
    ad_id,
    ifnull(round(sum(case when action = 'Clicked' then 1 else 0 end) / sum(case when action = 'Clicked' or action = 'viewed' then 1 else 0 end) * 100,2),0) as ctr
from 
    ads
group by
    ad_id
order by
    ctr desc,ad_id
;

制作会话柱状图

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第10张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第11张图片
这道题需要我们制作一个表格,表格的每一行分别是统计一个数据段的内容。

由于它需要展示所有四个分段,即使该分段没有数据,即total为0,我们就不便使用常规的查询方法来查询结果。

对于这样的需求,我们可以将四个结果分开查询,并使用union将他们连接起来。这也是这道题的关键所在。

select '[0-5>' as bin,count(*) as total
from sessions
where duration / 60 >= 0 and duration / 60 < 5

union

select '[5-10>' as bin, count(*) as total
from sessions
where duration / 60 >= 5 and duration / 60 < 10

union

select '[10-15>' as bin,count(*) as total
from sessions
where duration / 60 >= 10 and duration / 60 < 15

union

select '15 or more' as bin,count(*) as total
from sessions
where duration / 60 >= 15
;

按日期分组销售产品

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第12张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第13张图片
这个题目,需要我们统计每个日期销售的商品数量和名称

那么毫无疑问,我们需要根据日期对数据进行分组

接着查询每个分组中元素的数量

最后使用group_concat,可以展示所有的产品名称,需要注意的是,产品名称的展示需要我们进行排序,而在group_concat中进行排序,就直接在所有内容后面使用group by就可以了。对了,记得去重

select
    sell_date,
    count(distinct product) as num_sold,
    group_concat(distinct product order by product) as products
from 
    activities
group by
    sell_date
;

消费者下单频率

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第14张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第15张图片
题目要求我们统计所有在六月和七月各自花费超过100的顾客

不难发现,要求的顾客是六月花费超过100,和七月花费超过100的顾客集合的交集

这里我们可以使用子查询分别查询出在六月和七月花费超过100的顾客在取他们的交集

或者,我们还可以使用另一个思路,通过聚合函数配合case-when来对其中元素进行筛选,进而分别统计出某顾客在七月和六月的花费,这样搞只需要使用一个子查询查询所有的用户id即可。

在这个子查询中,我们需要根据用户分组,然后筛选出所有满足条件的组,并报告他们的id。

select 
    customer_id,
    name
from 
    customers
where
    customer_id in(
        select
            customer_id
        from 
            orders o 
            join product p on o.product_id = p.product_id 
        group by
            o.customer_id
        having 
            sum(case when order_date between '2020-06-01' and '2020-06-30' then quantity * price else 0 end) >= 100
            and 
            sum(case when order_date between '2020-07-01' and '2020-07-31' then quantity * price else 0 end) >= 100
    )
;

产品名称格式修复

题目链接
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第16张图片
【LeetCode数据库】 题目总结——经典题目题解与分析(三)_第17张图片
题目需要我们修复所有的产品名称,需要去掉名称中前后的空格,并将所有的字母变成小写

这个题实际上是一个考验字符串处理的题目。

将大小写统一可以使用lowerupper函数来完成。

去掉字符串中的前后空格可以使用trim函数来完成

使用这两个函数,就可以完成本题的需求了。

select
    product_name,
    sale_date,
    count(*) as total
from 
    (
        select
            lower(trim(product_name)) as product_name,
            substring(sale_date,1,7) as sale_date
        from 
            sales
    ) as s
group by
    product_name,sale_date
order by
    product_name , sale_date
;

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