美文网首页
sql刷题笔记(六)

sql刷题笔记(六)

作者: 顾子豪 | 来源:发表于2021-06-25 17:05 被阅读0次

    题目选自leetcode 上的题库

    可能不一定都是最优解,答案仅供参考

    每道题后面都应相应的难度等级,如果没时间做的话 可以在leetcode 按出题频率刷题

    祝大家面试取得好的成绩

    1350. 院系无效的学生

    难度简单

    SQL架构

    院系表: Departments

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    +---------------+---------+
    id 是该表的主键
    该表包含一所大学每个院系的 id 信息
    

    学生表: Students

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    | department_id | int     |
    +---------------+---------+
    id 是该表的主键
    该表包含一所大学每个学生的 id 和他/她就读的院系信息
    

    写一条 SQL 语句以查询那些所在院系不存在的学生的 id 和姓名

    可以以任何顺序返回结果

    下面是返回结果格式的例子

    Departments 表:
    +------+--------------------------+
    | id   | name                     |
    +------+--------------------------+
    | 1    | Electrical Engineering   |
    | 7    | Computer Engineering     |
    | 13   | Bussiness Administration |
    +------+--------------------------+
    
    Students 表:
    +------+----------+---------------+
    | id   | name     | department_id |
    +------+----------+---------------+
    | 23   | Alice    | 1             |
    | 1    | Bob      | 7             |
    | 5    | Jennifer | 13            |
    | 2    | John     | 14            |
    | 4    | Jasmine  | 77            |
    | 3    | Steve    | 74            |
    | 6    | Luis     | 1             |
    | 8    | Jonathan | 7             |
    | 7    | Daiana   | 33            |
    | 11   | Madelynn | 1             |
    +------+----------+---------------+
    
    结果表:
    +------+----------+
    | id   | name     |
    +------+----------+
    | 2    | John     |
    | 7    | Daiana   |
    | 4    | Jasmine  |
    | 3    | Steve    |
    +------+----------+
    
    John, Daiana, Steve 和 Jasmine 所在的院系分别是 14, 33, 74 和 77, 其中 14, 33, 74 和 77 并不存在于院系表
    
    select id,name  
    from Students 
    where department_id not in 
    (
        select id 
        from Departments
    )
    

    1355. 活动参与者

    难度中等

    SQL架构

    表: Friends

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    | activity      | varchar |
    +---------------+---------+
    id 是朋友的 id 和该表的主键
    name 是朋友的名字
    activity 是朋友参加的活动的名字
    

    表: Activities

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    +---------------+---------+
    id 是该表的主键
    name 是活动的名字
    

    写一条 SQL 查询那些既没有最多,也没有最少参与者的活动的名字

    可以以任何顺序返回结果,Activities 表的每项活动的参与者都来自 Friends 表

    下面是查询结果格式的例子:

    Friends 表:
    +------+--------------+---------------+
    | id   | name         | activity      |
    +------+--------------+---------------+
    | 1    | Jonathan D.  | Eating        |
    | 2    | Jade W.      | Singing       |
    | 3    | Victor J.    | Singing       |
    | 4    | Elvis Q.     | Eating        |
    | 5    | Daniel A.    | Eating        |
    | 6    | Bob B.       | Horse Riding  |
    +------+--------------+---------------+
    
    Activities 表:
    +------+--------------+
    | id   | name         |
    +------+--------------+
    | 1    | Eating       |
    | 2    | Singing      |
    | 3    | Horse Riding |
    +------+--------------+
    
    Result 表:
    +--------------+
    | activity     |
    +--------------+
    | Singing      |
    +--------------+
    
    Eating 活动有三个人参加, 是最多人参加的活动 (Jonathan D. , Elvis Q. and Daniel A.)
    Horse Riding 活动有一个人参加, 是最少人参加的活动 (Bob B.)
    Singing 活动有两个人参加 (Victor J. and Jade W.)
    
        select activity
        from (
            select activity,
            rank()over(order by cnt) rk1,
            rank()over(order by cnt desc) rk2
            from
            (
                select  activity  ,count(*) cnt
                from  Friends
                group by  activity 
            )t1
        )t2
        where rk1 !=1 and rk2 != 1
    

    不需要关联 Activities表,因为 至少有一人参加

    1364. 顾客的可信联系人数量

    难度中等

    SQL架构

    顾客表:Customers

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | customer_id   | int     |
    | customer_name | varchar |
    | email         | varchar |
    +---------------+---------+
    customer_id 是这张表的主键。
    此表的每一行包含了某在线商店顾客的姓名和电子邮件。
    

    联系方式表:Contacts

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | user_id       | id      |
    | contact_name  | varchar |
    | contact_email | varchar |
    +---------------+---------+
    (user_id, contact_email) 是这张表的主键。
    此表的每一行表示编号为 user_id 的顾客的某位联系人的姓名和电子邮件。
    此表包含每位顾客的联系人信息,但顾客的联系人不一定存在于顾客表中。
    

    发票表:Invoices

    +--------------+---------+
    | Column Name  | Type    |
    +--------------+---------+
    | invoice_id   | int     |
    | price        | int     |
    | user_id      | int     |
    +--------------+---------+
    invoice_id 是这张表的主键。
    此表的每一行分别表示编号为 user_id 的顾客拥有有一张编号为 invoice_id、价格为 price 的发票。
    

    为每张发票 invoice_id 编写一个SQL查询以查找以下内容:

    • customer_name:与发票相关的顾客名称。
    • price:发票的价格。
    • contacts_cnt:该顾客的联系人数量。
    • trusted_contacts_cnt:可信联系人的数量:既是该顾客的联系人又是商店顾客的联系人数量(即:可信联系人的电子邮件存在于客户表中)。

    将查询的结果按照 invoice_id 排序。

    查询结果的格式如下例所示:

    Customers table:
    +-------------+---------------+--------------------+
    | customer_id | customer_name | email              |
    +-------------+---------------+--------------------+
    | 1           | Alice         | alice@leetcode.com |
    | 2           | Bob           | bob@leetcode.com   |
    | 13          | John          | john@leetcode.com  |
    | 6           | Alex          | alex@leetcode.com  |
    +-------------+---------------+--------------------+
    Contacts table:
    +-------------+--------------+--------------------+
    | user_id     | contact_name | contact_email      |
    +-------------+--------------+--------------------+
    | 1           | Bob          | bob@leetcode.com   |
    | 1           | John         | john@leetcode.com  |
    | 1           | Jal          | jal@leetcode.com   |
    | 2           | Omar         | omar@leetcode.com  |
    | 2           | Meir         | meir@leetcode.com  |
    | 6           | Alice        | alice@leetcode.com |
    +-------------+--------------+--------------------+
    Invoices table:
    +------------+-------+---------+
    | invoice_id | price | user_id |
    +------------+-------+---------+
    | 77         | 100   | 1       |
    | 88         | 200   | 1       |
    | 99         | 300   | 2       |
    | 66         | 400   | 2       |
    | 55         | 500   | 13      |
    | 44         | 60    | 6       |
    +------------+-------+---------+
    Result table:
    +------------+---------------+-------+--------------+----------------------+
    | invoice_id | customer_name | price | contacts_cnt | trusted_contacts_cnt |
    +------------+---------------+-------+--------------+----------------------+
    | 44         | Alex          | 60    | 1            | 1                    |
    | 55         | John          | 500   | 0            | 0                    |
    | 66         | Bob           | 400   | 2            | 0                    |
    | 77         | Alice         | 100   | 3            | 2                    |
    | 88         | Alice         | 200   | 3            | 2                    |
    | 99         | Bob           | 300   | 2            | 0                    |
    +------------+---------------+-------+--------------+----------------------+
    Alice 有三位联系人,其中两位(Bob 和 John)是可信联系人。
    Bob 有两位联系人, 他们中的任何一位都不是可信联系人。
    Alex 只有一位联系人(Alice),并是一位可信联系人。
    John 没有任何联系人。
    
    select invoice_id ,customer_name,price,ifnull(cnt,0) contacts_cnt,ifnull(bc,0) trusted_contacts_cnt 
    from Invoices i
    left join (
    select user_id ,count(*) cnt
    from Contacts
    group by user_id
    ) t1
    on i.user_id=t1.user_id
    left join (
    select  user_id ,count(*) bc
    from Contacts
        where contact_name in
        (
            select customer_name
            from Customers
        )
    group by user_id 
    )t2
    on i.user_id = t2.user_id
    left join Customers c
    on i.user_id= c.customer_id
    order by invoice_id
    

    就是麻烦点 各种join

    1369. 获取最近第二次的活动

    难度困难

    SQL架构

    表: UserActivity

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | username      | varchar |
    | activity      | varchar |
    | startDate     | Date    |
    | endDate       | Date    |
    +---------------+---------+
    该表不包含主键
    该表包含每个用户在一段时间内进行的活动的信息
    名为 username 的用户在 startDate 到 endDate 日内有一次活动
    

    写一条SQL查询展示每一位用户 最近第二次 的活动

    如果用户仅有一次活动,返回该活动

    一个用户不能同时进行超过一项活动,以 任意 顺序返回结果

    下面是查询结果格式的例子:

    UserActivity 表:
    +------------+--------------+-------------+-------------+
    | username   | activity     | startDate   | endDate     |
    +------------+--------------+-------------+-------------+
    | Alice      | Travel       | 2020-02-12  | 2020-02-20  |
    | Alice      | Dancing      | 2020-02-21  | 2020-02-23  |
    | Alice      | Travel       | 2020-02-24  | 2020-02-28  |
    | Bob        | Travel       | 2020-02-11  | 2020-02-18  |
    +------------+--------------+-------------+-------------+
    
    Result 表:
    +------------+--------------+-------------+-------------+
    | username   | activity     | startDate   | endDate     |
    +------------+--------------+-------------+-------------+
    | Alice      | Dancing      | 2020-02-21  | 2020-02-23  |
    | Bob        | Travel       | 2020-02-11  | 2020-02-18  |
    +------------+--------------+-------------+-------------+
    
    Alice 最近第二次的活动是从 2020-02-24 到 2020-02-28 的旅行, 在此之前的 2020-02-21 到 2020-02-23 她进行了舞蹈
    Bob 只有一条记录,我们就取这条记录
    
    select username, activity ,startDate,endDate 
    from 
    (
    select username, activity ,startDate,endDate ,
        rank()over(partition by username order by startDate desc) rk,
        lag( startDate ,1,null)over(partition by username order by startDate ) lg
    from UserActivity
    )t1
    where rk=2 or  (rk = 1 &&  lg is null)
    

    1378. 使用唯一标识码替换员工ID

    难度简单

    SQL架构

    Employees 表:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    +---------------+---------+
    id 是这张表的主键。
    这张表的每一行分别代表了某公司其中一位员工的名字和 ID 。
    

    EmployeeUNI 表:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | unique_id     | int     |
    +---------------+---------+
    (id, unique_id) 是这张表的主键。
    这张表的每一行包含了该公司某位员工的 ID 和他的唯一标识码(unique ID)。
    

    写一段SQL查询来展示每位用户的 唯一标识码(unique ID );如果某位员工没有唯一标识码,使用 null 填充即可。

    你可以以 任意 顺序返回结果表。

    查询结果的格式如下例所示:

    Employees table:
    +----+----------+
    | id | name     |
    +----+----------+
    | 1  | Alice    |
    | 7  | Bob      |
    | 11 | Meir     |
    | 90 | Winston  |
    | 3  | Jonathan |
    +----+----------+
    
    EmployeeUNI table:
    +----+-----------+
    | id | unique_id |
    +----+-----------+
    | 3  | 1         |
    | 11 | 2         |
    | 90 | 3         |
    +----+-----------+
    
    EmployeeUNI table:
    +-----------+----------+
    | unique_id | name     |
    +-----------+----------+
    | null      | Alice    |
    | null      | Bob      |
    | 2         | Meir     |
    | 3         | Winston  |
    | 1         | Jonathan |
    +-----------+----------+
    
    Alice and Bob 没有唯一标识码, 因此我们使用 null 替代。
    Meir 的唯一标识码是 2 。
    Winston 的唯一标识码是 3 。
    Jonathan 唯一标识码是 1 。
    
    select unique_id,e.name
    from Employees  e left join EmployeeUNI u
    on e.id = u.id
    

    1384. 按年度列出销售总额

    难度困难

    SQL架构

    Product 表:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | product_id    | int     |
    | product_name  | varchar |
    +---------------+---------+
    product_id 是这张表的主键。
    product_name 是产品的名称。
    

    Sales 表:

    +---------------------+---------+
    | Column Name         | Type    |
    +---------------------+---------+
    | product_id          | int     |
    | period_start        | varchar |
    | period_end          | date    |
    | average_daily_sales | int     |
    +---------------------+---------+
    product_id 是这张表的主键。
    period_start 和 period_end 是该产品销售期的起始日期和结束日期,且这两个日期包含在销售期内。
    average_daily_sales 列存储销售期内该产品的日平均销售额。
    

    编写一段SQL查询每个产品每年的总销售额,并包含 product_id, product_name 以及 report_year 等信息。

    销售年份的日期介于 2018 年到 2020 年之间。你返回的结果需要按 product_id 和 report_year 排序

    查询结果格式如下例所示:

    Product table:
    +------------+--------------+
    | product_id | product_name |
    +------------+--------------+
    | 1          | LC Phone     |
    | 2          | LC T-Shirt   |
    | 3          | LC Keychain  |
    +------------+--------------+
    
    Sales table:
    +------------+--------------+-------------+---------------------+
    | product_id | period_start | period_end  | average_daily_sales |
    +------------+--------------+-------------+---------------------+
    | 1          | 2019-01-25   | 2019-02-28  | 100                 |
    | 2          | 2018-12-01   | 2020-01-01  | 10                  |
    | 3          | 2019-12-01   | 2020-01-31  | 1                   |
    +------------+--------------+-------------+---------------------+
    
    Result table:
    +------------+--------------+-------------+--------------+
    | product_id | product_name | report_year | total_amount |
    +------------+--------------+-------------+--------------+
    | 1          | LC Phone     |    2019     | 3500         |
    | 2          | LC T-Shirt   |    2018     | 310          |
    | 2          | LC T-Shirt   |    2019     | 3650         |
    | 2          | LC T-Shirt   |    2020     | 10           |
    | 3          | LC Keychain  |    2019     | 31           |
    | 3          | LC Keychain  |    2020     | 31           |
    +------------+--------------+-------------+--------------+
    LC Phone 在 2019-01-25 至 2019-02-28 期间销售,该产品销售时间总计35天。销售总额 35*100 = 3500。
    LC T-shirt 在 2018-12-01 至 2020-01-01 期间销售,该产品在2018年、2019年、2020年的销售时间分别是31天、365天、1天,2018年、2019年、2020年的销售总额分别是31*10=310、365*10=3650、1*10=10。
    LC Keychain 在 2019-12-01 至 2020-01-31 期间销售,该产品在2019年、2020年的销售时间分别是:31天、31天,2019年、2020年的销售总额分别是31*1=31、31*1=31。
    
    (
     select Sales.product_id, product_name, '2018' as 'report_year', if(period_start<'2019-01-01', (datediff(if(period_end<'2019-01-01', period_end, date('2018-12-31')), if(period_start>='2018-01-01', period_start, date('2018-01-01')))+1)*average_daily_sales, 0) as total_amount
    from Sales  
    join Product on Sales.product_id = Product.product_id 
    having  total_amount>0
    )
    union(
    select Sales.product_id, product_name, '2019' as 'report_year', if( period_start<'2020-01-01', (datediff(if(period_end<'2020-01-01', period_end, date('2019-12-31')), if(period_start>='2019-01-01', period_start, date('2019-01-01')))+1)*average_daily_sales , 0) as total_amount
    from Sales  
    join Product on (Sales.product_id = Product.product_id )
    having  total_amount>0
    )
    union(
    select Sales.product_id, product_name, '2020' as 'report_year', (datediff(if(period_end<'2021-01-01', period_end, date('2020-12-31')), if(period_start>='2020-01-01', period_start, date('2020-01-01')))+1)*average_daily_sales as total_amount
    from Sales  
    join Product  on (Sales.product_id = Product.product_id)
    having total_amount>0
    ) 
    order by product_id, report_year
    

    各个年份进行union,就是年份判断的时候麻烦些

    1393. 股票的资本损益

    难度中等

    SQL架构

    Stocks 表:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | stock_name    | varchar |
    | operation     | enum    |
    | operation_day | int     |
    | price         | int     |
    +---------------+---------+
    (stock_name, day) 是这张表的主键
    operation 列使用的是一种枚举类型,包括:('Sell','Buy')
    此表的每一行代表了名为 stock_name 的某支股票在 operation_day 这一天的操作价格。
    保证股票的每次'Sell'操作前,都有相应的'Buy'操作。
    

    编写一个SQL查询来报告每支股票的资本损益。

    股票的资本损益是一次或多次买卖股票后的全部收益或损失。

    以任意顺序返回结果即可。

    SQL查询结果的格式如下例所示:

    Stocks 表:
    +---------------+-----------+---------------+--------+
    | stock_name    | operation | operation_day | price  |
    +---------------+-----------+---------------+--------+
    | Leetcode      | Buy       | 1             | 1000   |
    | Corona Masks  | Buy       | 2             | 10     |
    | Leetcode      | Sell      | 5             | 9000   |
    | Handbags      | Buy       | 17            | 30000  |
    | Corona Masks  | Sell      | 3             | 1010   |
    | Corona Masks  | Buy       | 4             | 1000   |
    | Corona Masks  | Sell      | 5             | 500    |
    | Corona Masks  | Buy       | 6             | 1000   |
    | Handbags      | Sell      | 29            | 7000   |
    | Corona Masks  | Sell      | 10            | 10000  |
    +---------------+-----------+---------------+--------+
    
    Result 表:
    +---------------+-------------------+
    | stock_name    | capital_gain_loss |
    +---------------+-------------------+
    | Corona Masks  | 9500              |
    | Leetcode      | 8000              |
    | Handbags      | -23000            |
    +---------------+-------------------+
    Leetcode 股票在第一天以1000美元的价格买入,在第五天以9000美元的价格卖出。资本收益=9000-1000=8000美元。
    Handbags 股票在第17天以30000美元的价格买入,在第29天以7000美元的价格卖出。资本损失=7000-30000=-23000美元。
    Corona Masks 股票在第1天以10美元的价格买入,在第3天以1010美元的价格卖出。在第4天以1000美元的价格再次购买,在第5天以500美元的价格出售。最后,它在第6天以1000美元的价格被买走,在第10天以10000美元的价格被卖掉。资本损益是每次(’Buy'->'Sell')操作资本收益或损失的和=(1010-10)+(500-1000)+(10000-1000)=1000-500+9000=9500美元。
    
    select stock_name,sell-buy capital_gain_loss
    from(
    select stock_name ,
           sum(if(operation='Buy', price,0))over(partition by stock_name ) buy,
           sum(if(operation='Sell',price,0))over(partition by stock_name) sell
    from Stocks s
    )t1
    group by stock_name,buy,sell
    

    1398. 购买了产品A和产品B却没有购买产品C的顾客

    难度中等

    SQL架构

    Customers 表:

    +---------------------+---------+
    | Column Name         | Type    |
    +---------------------+---------+
    | customer_id         | int     |
    | customer_name       | varchar |
    +---------------------+---------+
    customer_id 是这张表的主键。
    customer_name 是顾客的名称。
    

    Orders 表:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | order_id      | int     |
    | customer_id   | int     |
    | product_name  | varchar |
    +---------------+---------+
    order_id 是这张表的主键。
    customer_id 是购买了名为 "product_name" 产品顾客的id。
    

    请你设计 SQL 查询来报告购买了产品 A 和产品 B 却没有购买产品 C 的顾客的 ID 和姓名( customer_idcustomer_name ),我们将基于此结果为他们推荐产品 C 。
    您返回的查询结果需要按照 customer_id 排序

    查询结果如下例所示。

    Customers table:
    +-------------+---------------+
    | customer_id | customer_name |
    +-------------+---------------+
    | 1           | Daniel        |
    | 2           | Diana         |
    | 3           | Elizabeth     |
    | 4           | Jhon          |
    +-------------+---------------+
    
    Orders table:
    +------------+--------------+---------------+
    | order_id   | customer_id  | product_name  |
    +------------+--------------+---------------+
    | 10         |     1        |     A         |
    | 20         |     1        |     B         |
    | 30         |     1        |     D         |
    | 40         |     1        |     C         |
    | 50         |     2        |     A         |
    | 60         |     3        |     A         |
    | 70         |     3        |     B         |
    | 80         |     3        |     D         |
    | 90         |     4        |     C         |
    +------------+--------------+---------------+
    
    Result table:
    +-------------+---------------+
    | customer_id | customer_name |
    +-------------+---------------+
    | 3           | Elizabeth     |
    +-------------+---------------+
    只有 customer_id 为 3 的顾客购买了产品 A 和产品 B ,却没有购买产品 C 。
    
    select  o.customer_id, customer_name 
    from Orders o left join  Customers c
    on o.customer_id=c.customer_id
    group by customer_id
    having sum(product_name ='A')>=1 and sum(product_name='B')>=1 and sum(product_name='C')=0
    

    1407. 排名靠前的旅行者

    难度简单

    SQL架构

    表单: Users

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    +---------------+---------+
    id 是该表单主键.
    name 是用户名字.
    

    表单: Rides

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | user_id       | int     |
    | distance      | int     |
    +---------------+---------+
    id 是该表单主键.
    user_id 是本次行程的用户的 id, 而该用户此次行程距离为 distance.
    

    写一段 SQL , 报告每个用户的旅行距离.

    返回的结果表单, 以 travelled_distance 降序排列, 如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列.

    查询结果格式, 如下例所示.

    Users 表单:
    +------+-----------+
    | id   | name      |
    +------+-----------+
    | 1    | Alice     |
    | 2    | Bob       |
    | 3    | Alex      |
    | 4    | Donald    |
    | 7    | Lee       |
    | 13   | Jonathan  |
    | 19   | Elvis     |
    +------+-----------+
    
    Rides 表单:
    +------+----------+----------+
    | id   | user_id  | distance |
    +------+----------+----------+
    | 1    | 1        | 120      |
    | 2    | 2        | 317      |
    | 3    | 3        | 222      |
    | 4    | 7        | 100      |
    | 5    | 13       | 312      |
    | 6    | 19       | 50       |
    | 7    | 7        | 120      |
    | 8    | 19       | 400      |
    | 9    | 7        | 230      |
    +------+----------+----------+
    
    Result 表单:
    +----------+--------------------+
    | name     | travelled_distance |
    +----------+--------------------+
    | Elvis    | 450                |
    | Lee      | 450                |
    | Bob      | 317                |
    | Jonathan | 312                |
    | Alex     | 222                |
    | Alice    | 120                |
    | Donald   | 0                  |
    +----------+--------------------+
    Elvis 和 Lee 旅行了 450 英里, Elvis 是排名靠前的旅行者, 因为他的名字在字母表上的排序比 Lee 更小.
    Bob, Jonathan, Alex 和 Alice 只有一次行程, 我们只按此次行程的全部距离对他们排序.
    Donald 没有任何行程, 他的旅行距离为 0.
    
    select name,sum(ifnull(distance,0)) travelled_distance 
    from Users u left join Rides r
    on u.id = r.user_id
    group by name
    order by travelled_distance  desc, name 
    

    1412. 查找成绩处于中游的学生

    难度困难

    SQL架构

    表: Student

    +---------------------+---------+
    | Column Name         | Type    |
    +---------------------+---------+
    | student_id          | int     |
    | student_name        | varchar |
    +---------------------+---------+
    student_id 是该表主键.
    student_name 学生名字.
    

    表: Exam

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | exam_id       | int     |
    | student_id    | int     |
    | score         | int     |
    +---------------+---------+
    (exam_id, student_id) 是该表主键.
    学生 student_id 在测验 exam_id 中得分为 score.
    

    成绩处于中游的学生是指至少参加了一次测验, 且得分既不是最高分也不是最低分的学生。

    写一个 SQL 语句,找出在所有测验中都处于中游的学生 (student_id, student_name)

    不要返回从来没有参加过测验的学生。返回结果表按照 student_id 排序。

    查询结果格式如下。

    Student 表:
    +-------------+---------------+
    | student_id  | student_name  |
    +-------------+---------------+
    | 1           | Daniel        |
    | 2           | Jade          |
    | 3           | Stella        |
    | 4           | Jonathan      |
    | 5           | Will          |
    +-------------+---------------+
    
    Exam 表:
    +------------+--------------+-----------+
    | exam_id    | student_id   | score     |
    +------------+--------------+-----------+
    | 10         |     1        |    70     |
    | 10         |     2        |    80     |
    | 10         |     3        |    90     |
    | 20         |     1        |    80     |
    | 30         |     1        |    70     |
    | 30         |     3        |    80     |
    | 30         |     4        |    90     |
    | 40         |     1        |    60     |
    | 40         |     2        |    70     |
    | 40         |     4        |    80     |
    +------------+--------------+-----------+
    
    Result 表:
    +-------------+---------------+
    | student_id  | student_name  |
    +-------------+---------------+
    | 2           | Jade          |
    +-------------+---------------+
    
    对于测验 1: 学生 1 和 3 分别获得了最低分和最高分。
    对于测验 2: 学生 1 既获得了最高分, 也获得了最低分。
    对于测验 3 和 4: 学生 1 和 4 分别获得了最低分和最高分。
    学生 2 和 5 没有在任一场测验中获得了最高分或者最低分。
    因为学生 5 从来没有参加过任何测验, 所以他被排除于结果表。
    由此, 我们仅仅返回学生 2 的信息。
    
    select e.student_id,student_name
    from Exam e left join Student s
    on e.student_id=s.student_id
    where e.student_id not in(
        select student_id
        from(
            select student_id,rank() over(partition by exam_id order by score desc) rkmax, rank() over(partition by exam_id order by score ) rkmin
            from Exam 
        )t1
        where rkmax = 1 or rkmin =1
    )
    group by e.student_id,student_name
    order by e.student_id 
    

    1421. 净现值查询

    难度中等

    SQL架构

    表: NPV

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | year          | int     |
    | npv           | int     |
    +---------------+---------+
    (id, year) 是该表主键.
    该表有每一笔存货的年份, id 和对应净现值的信息.
    

    表: Queries

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | year          | int     |
    +---------------+---------+
    (id, year) 是该表主键.
    该表有每一次查询所对应存货的 id 和年份的信息.
    

    写一个 SQL, 找到 Queries 表中每一次查询的净现值.

    结果表没有顺序要求.

    查询结果的格式如下所示:

    NPV 表:
    +------+--------+--------+
    | id   | year   | npv    |
    +------+--------+--------+
    | 1    | 2018   | 100    |
    | 7    | 2020   | 30     |
    | 13   | 2019   | 40     |
    | 1    | 2019   | 113    |
    | 2    | 2008   | 121    |
    | 3    | 2009   | 12     |
    | 11   | 2020   | 99     |
    | 7    | 2019   | 0      |
    +------+--------+--------+
    
    Queries 表:
    +------+--------+
    | id   | year   |
    +------+--------+
    | 1    | 2019   |
    | 2    | 2008   |
    | 3    | 2009   |
    | 7    | 2018   |
    | 7    | 2019   |
    | 7    | 2020   |
    | 13   | 2019   |
    +------+--------+
    
    结果表:
    +------+--------+--------+
    | id   | year   | npv    |
    +------+--------+--------+
    | 1    | 2019   | 113    |
    | 2    | 2008   | 121    |
    | 3    | 2009   | 12     |
    | 7    | 2018   | 0      |
    | 7    | 2019   | 0      |
    | 7    | 2020   | 30     |
    | 13   | 2019   | 40     |
    +------+--------+--------+
    
    (7, 2018)的净现值不在 NPV 表中, 我们把它看作是 0.
    所有其它查询的净现值都能在 NPV 表中找到.
    
    select q.id,q.year,ifnull(npv,0) npv
    from Queries q left join NPV n
    on q.id = n.id and q.year = n.year
    

    npv 净现值概念 了解下

    1435. 制作会话柱状图

    难度简单

    SQL架构

    表:Sessions

    +---------------------+---------+
    | Column Name         | Type    |
    +---------------------+---------+
    | session_id          | int     |
    | duration            | int     |
    +---------------------+---------+
    session_id 是该表主键
    duration 是用户访问应用的时间, 以秒为单位
    

    你想知道用户在你的 app 上的访问时长情况。因此决定统计访问时长区间分别为 "[0-5>", "[5-10>", "[10-15>" 和 "15 or more" (单位:分钟)的会话数量,并以此绘制柱状图。

    写一个SQL查询来报告(访问时长区间,会话总数)。结果可用任何顺序呈现。

    下方为查询的输出格式:

    Sessions 表:
    +-------------+---------------+
    | session_id  | duration      |
    +-------------+---------------+
    | 1           | 30            |
    | 2           | 199           |
    | 3           | 299           |
    | 4           | 580           |
    | 5           | 1000          |
    +-------------+---------------+
    
    Result 表:
    +--------------+--------------+
    | bin          | total        |
    +--------------+--------------+
    | [0-5>        | 3            |
    | [5-10>       | 1            |
    | [10-15>      | 0            |
    | 15 or more   | 1            |
    +--------------+--------------+
    
    对于 session_id 1,2 和 3 ,它们的访问时间大于等于 0 分钟且小于 5 分钟。
    对于 session_id 4,它的访问时间大于等于 5 分钟且小于 10 分钟。
    没有会话的访问时间大于等于 10 分钟且小于 15 分钟。
    对于 session_id 5, 它的访问时间大于等于 15 分钟。
    

    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
    

    还有很多其他解法

    select a.bin, count(b.bin) as total
    from
    (
        select '[0-5>' as bin union select '[5-10>' as bin union select '[10-15>' as bin union select '15 or more' as bin 
    )a
    left join 
    (
        select case
            when duration < 300 then '[0-5>'
            when duration >= 300 and duration < 600 then '[5-10>'
            when duration >= 600 and duration < 900 then '[10-15>'
            else '15 or more'
            end bin
        from Sessions 
    )b
    on a.bin = b.bin
    group by a.bin
    

    1440. 计算布尔表达式的值

    难度中等

    SQL架构

    Variables:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | name          | varchar |
    | value         | int     |
    +---------------+---------+
    name 是该表主键.
    该表包含了存储的变量及其对应的值.
    

    Expressions:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | left_operand  | varchar |
    | operator      | enum    |
    | right_operand | varchar |
    +---------------+---------+
    (left_operand, operator, right_operand) 是该表主键.
    该表包含了需要计算的布尔表达式.
    operator 是枚举类型, 取值于('<', '>', '=')
    left_operand 和 right_operand 的值保证存在于 Variables 表单中.
    

    写一个 SQL 查询, 以计算表 Expressions 中的布尔表达式.

    返回的结果表没有顺序要求.

    查询结果格式如下例所示.

    Variables 表:
    +------+-------+
    | name | value |
    +------+-------+
    | x    | 66    |
    | y    | 77    |
    +------+-------+
    
    Expressions 表:
    +--------------+----------+---------------+
    | left_operand | operator | right_operand |
    +--------------+----------+---------------+
    | x            | >        | y             |
    | x            | <        | y             |
    | x            | =        | y             |
    | y            | >        | x             |
    | y            | <        | x             |
    | x            | =        | x             |
    +--------------+----------+---------------+
    
    Result 表:
    +--------------+----------+---------------+-------+
    | left_operand | operator | right_operand | value |
    +--------------+----------+---------------+-------+
    | x            | >        | y             | false |
    | x            | <        | y             | true  |
    | x            | =        | y             | false |
    | y            | >        | x             | true  |
    | y            | <        | x             | false |
    | x            | =        | x             | true  |
    +--------------+----------+---------------+-------+
    如上所示, 你需要通过使用 Variables 表来找到 Expressions 表中的每一个布尔表达式的值.
    
    select e.left_operand,e.operator,e.right_operand,
    case e.operator
        when '>' then if(v1.value>v2.value,'true','false')
        when '<' then if(v1.value<v2.value,'true','false')
        else  if(v1.value=v2.value,'true','false')
    end value
    from Expressions e
    left join Variables v1 on v1.name = e.left_operand 
    left join Variables v2 on v2.name = e.right_operand
    

    1445. 苹果和桔子

    难度中等

    SQL架构

    表: Sales

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | sale_date     | date    |
    | fruit         | enum    | 
    | sold_num      | int     | 
    +---------------+---------+
    (sale_date,fruit) 是该表主键.
    该表包含了每一天中"苹果" 和 "桔子"的销售情况.
    

    写一个 SQL 查询, 报告每一天 苹果桔子 销售的数目的差异.

    返回的结果表, 按照格式为 ('YYYY-MM-DD') 的 sale_date 排序.

    查询结果表如下例所示:

    Sales 表:
    +------------+------------+-------------+
    | sale_date  | fruit      | sold_num    |
    +------------+------------+-------------+
    | 2020-05-01 | apples     | 10          |
    | 2020-05-01 | oranges    | 8           |
    | 2020-05-02 | apples     | 15          |
    | 2020-05-02 | oranges    | 15          |
    | 2020-05-03 | apples     | 20          |
    | 2020-05-03 | oranges    | 0           |
    | 2020-05-04 | apples     | 15          |
    | 2020-05-04 | oranges    | 16          |
    +------------+------------+-------------+
    
    Result 表:
    +------------+--------------+
    | sale_date  | diff         |
    +------------+--------------+
    | 2020-05-01 | 2            |
    | 2020-05-02 | 0            |
    | 2020-05-03 | 20           |
    | 2020-05-04 | -1           |
    +------------+--------------+
    
    在 2020-05-01, 卖了 10 个苹果 和 8 个桔子 (差异为 10 - 8 = 2).
    在 2020-05-02, 卖了 15 个苹果 和 15 个桔子 (差异为 15 - 15 = 0).
    在 2020-05-03, 卖了 20 个苹果 和 0 个桔子 (差异为 20 - 0 = 20).
    在 2020-05-04, 卖了 15 个苹果 和 16 个桔子 (差异为 15 - 16 = -1).
    
    select  sale_date,sold_num-ld diff
    from 
    (
    select sale_date,sold_num , fruit ,lead(sold_num ,1,null) over(partition by  sale_date ) ld
    from Sales
    )t1
    where fruit='apples'
    

    1454. 活跃用户

    难度中等

    SQL架构

    Accounts:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | name          | varchar |
    +---------------+---------+
    id 是该表主键.
    该表包含账户 id 和账户的用户名.
    

    Logins:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | login_date    | date    |
    +---------------+---------+
    该表无主键, 可能包含重复项.
    该表包含登录用户的账户 id 和登录日期. 用户也许一天内登录多次.
    

    写一个 SQL 查询, 找到活跃用户的 id 和 name.

    活跃用户是指那些至少连续 5 天登录账户的用户.

    返回的结果表按照 id 排序.

    结果表格式如下例所示:

    Accounts 表:
    +----+----------+
    | id | name     |
    +----+----------+
    | 1  | Winston  |
    | 7  | Jonathan |
    +----+----------+
    
    Logins 表:
    +----+------------+
    | id | login_date |
    +----+------------+
    | 7  | 2020-05-30 |
    | 1  | 2020-05-30 |
    | 7  | 2020-05-31 |
    | 7  | 2020-06-01 |
    | 7  | 2020-06-02 |
    | 7  | 2020-06-02 |
    | 7  | 2020-06-03 |
    | 1  | 2020-06-07 |
    | 7  | 2020-06-10 |
    +----+------------+
    
    Result 表:
    +----+----------+
    | id | name     |
    +----+----------+
    | 7  | Jonathan |
    +----+----------+
    id = 1 的用户 Winston 仅仅在不同的 2 天内登录了 2 次, 所以, Winston 不是活跃用户.
    id = 7 的用户 Jonathon 在不同的 6 天内登录了 7 次, , 6 天中有 5 天是连续的, 所以, Jonathan 是活跃用户.
    

    后续问题:
    如果活跃用户是那些至少连续 n 天登录账户的用户, 你能否写出通用的解决方案?

    select t3.id,name
    from 
    (
        select distinct id
        from 
        (
            select id,login_date,lead(login_date,4,null) over(partition by id order by login_date) ld
            from 
            (
                select id,login_date 
                from Logins
                group by id,login_date
            )t1
        )t2
        where datediff(ld,login_date)=4
    )t3
    left join Accounts a
    on t3.id = a.id
    

    注意用户当天重复登入

    1459. 矩形面积

    难度中等

    SQL架构

    表: Points

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | x_value       | int     |
    | y_value       | int     |
    +---------------+---------+
    id 是该表主键.
    每个点都表示为二维空间 (x_value, y_value).
    

    写一个 SQL 语句, 报告由表中任意两点可以形成的所有可能的矩形.

    结果表中的每一行包含三列 (p1, p2, area) 如下:

    • p1p2 是矩形两个对角的 id 且 p1 < p2.
    • 矩形的面积由列 area 表示.

    请按照面积大小降序排列,如果面积相同的话, 则按照 p1 和 p2 升序对结果表排序

    Points 表:
    +----------+-------------+-------------+
    | id       | x_value     | y_value     |
    +----------+-------------+-------------+
    | 1        | 2           | 8           |
    | 2        | 4           | 7           |
    | 3        | 2           | 10          |
    +----------+-------------+-------------+
    
    Result 表:
    +----------+-------------+-------------+
    | p1       | p2          | area        |
    +----------+-------------+-------------+
    | 2        | 3           | 6           |
    | 1        | 2           | 2           |
    +----------+-------------+-------------+
    
    p1 应该小于 p2 并且面积大于 0.
    p1 = 1 且 p2 = 2 时, 面积等于 |2-4| * |8-7| = 2.
    p1 = 2 且 p2 = 3 时, 面积等于 |4-2| * |7-10| = 6.
    p1 = 1 且 p2 = 3 时, 是不可能为矩形的, 因为面积等于 0.
    
    select a.id P1,b.id P2,abs(a.x_value-b.x_value)*abs(a.y_value-b.y_value) as area
    from Points a,Points b
    where a.id<b.id and a.x_value != b.x_value and a.y_value != b.y_value
    order by area desc,P1 ,P2 
    

    相关文章

      网友评论

          本文标题:sql刷题笔记(六)

          本文链接:https://www.haomeiwen.com/subject/wagsyltx.html