【力扣 | SQL题 | 每日四题】力扣1571, 1715, 1699, 1445, 1495, 1683

时间:2024-10-03 21:14:24

1. 力扣1571:仓库经理

1.1 题目:

表: Warehouse

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| name         | varchar |
| product_id   | int     |
| units        | int     |
+--------------+---------+
(name, product_id) 是该表主键(具有唯一值的列的组合).
该表的行包含了每个仓库的所有商品信息.

表: Products

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| product_name  | varchar |
| Width         | int     |
| Length        | int     |
| Height        | int     |
+---------------+---------+
product_id 是该表主键(具有唯一值的列).
该表的行包含了每件商品以英尺为单位的尺寸(宽度, 长度和高度)信息.

编写解决方案报告每个仓库的存货量是多少立方英尺。

返回结果没有顺序要求。

返回结果格式如下例所示。

示例 1:

输入:
Warehouse 表:
+------------+--------------+-------------+
| name       | product_id   | units       |
+------------+--------------+-------------+
| LCHouse1   | 1            | 1           |
| LCHouse1   | 2            | 10          |
| LCHouse1   | 3            | 5           |
| LCHouse2   | 1            | 2           |
| LCHouse2   | 2            | 2           |
| LCHouse3   | 4            | 1           |
+------------+--------------+-------------+
Products 表:
+------------+--------------+------------+----------+-----------+
| product_id | product_name | Width      | Length   | Height    |
+------------+--------------+------------+----------+-----------+
| 1          | LC-TV        | 5          | 50       | 40        |
| 2          | LC-KeyChain  | 5          | 5        | 5         |
| 3          | LC-Phone     | 2          | 10       | 10        |
| 4          | LC-T-Shirt   | 4          | 10       | 20        |
+------------+--------------+------------+----------+-----------+
输出:
+----------------+------------+
| warehouse_name | volume     | 
+----------------+------------+
| LCHouse1       | 12250      | 
| LCHouse2       | 20250      |
| LCHouse3       | 800        |
+----------------+------------+
解释:
Id为1的商品(LC-TV)的存货量为 5x50x40 = 10000
Id为2的商品(LC-KeyChain)的存货量为 5x5x5 = 125 
Id为3的商品(LC-Phone)的存货量为 2x10x10 = 200
Id为4的商品(LC-T-Shirt)的存货量为 4x10x20 = 800
仓库LCHouse1: 1个单位的LC-TV + 10个单位的LC-KeyChain + 5个单位的LC-Phone.
          总存货量为: 1*10000 + 10*125  + 5*200 = 12250 立方英尺
仓库LCHouse2: 2个单位的LC-TV + 2个单位的LC-KeyChain.
          总存货量为: 2*10000 + 2*125 = 20250 立方英尺
仓库LCHouse3: 1个单位的LC-T-Shirt.
          总存货量为: 1*800 = 800 立方英尺.

1.2 思路:

简单题,通过率高达80%,不用多说。

1.3 题解:

-- 优化一下Products 表
with tep as (
    select product_id, product_name , Width*Length*Height wlh
    from Products p 
)
-- 简单的多表查询
select name warehouse_name, sum(wlh*units) volume
from Warehouse w 
join tep
on w.product_id = tep.product_id
group by name

2. 力扣1715:苹果和橘子的个数

2.1 题目:

表: Boxes

+--------------+------+
| Column Name  | Type |
+--------------+------+
| box_id       | int  |
| chest_id     | int  |
| apple_count  | int  |
| orange_count | int  |
+--------------+------+
box_id 是该表的主键。
chest_id 是 chests 表的外键。
该表包含大箱子 (box) 中包含的苹果和橘子的个数。每个大箱子中可能包含一个小盒子 (chest) ,小盒子中也包含若干苹果和橘子。

表: Chests

+--------------+------+
| Column Name  | Type |
+--------------+------+
| chest_id     | int  |
| apple_count  | int  |
| orange_count | int  |
+--------------+------+
chest_id 是该表的主键。
该表包含小盒子的信息,以及小盒子中包含的苹果和橘子的个数。

编写 SQL 语句,查询每个大箱子中苹果和橘子的个数。如果大箱子中包含小盒子,还应当包含小盒子中苹果和橘子的个数。

以任意顺序返回结果表。

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

示例 1:

输入:
Boxes 表:
+--------+----------+-------------+--------------+
| box_id | chest_id | apple_count | orange_count |
+--------+----------+-------------+--------------+
| 2      | null     | 6           | 15           |
| 18     | 14       | 4           | 15           |
| 19     | 3        | 8           | 4            |
| 12     | 2        | 19          | 20           |
| 20     | 6        | 12          | 9            |
| 8      | 6        | 9           | 9            |
| 3      | 14       | 16          | 7            |
+--------+----------+-------------+--------------+
Chests 表:
+----------+-------------+--------------+
| chest_id | apple_count | orange_count |
+----------+-------------+--------------+
| 6        | 5           | 6            |
| 14       | 20          | 10           |
| 2        | 8           | 8            |
| 3        | 19          | 4            |
| 16       | 19          | 19           |
+----------+-------------+--------------+
输出:
+-------------+--------------+
| apple_count | orange_count |
+-------------+--------------+
| 151         | 123          |
+-------------+--------------+
解释:
大箱子 2 中有 6 个苹果和 15 个橘子。
大箱子 18 中有 4 + 20 (在小盒子中) = 24 个苹果和 15 + 10 (在小盒子中) = 25 个橘子。
大箱子 19 中有 8 + 19 (在小盒子中) = 27 个苹果和 4 + 4 (在小盒子中) = 8 个橘子。
大箱子 12 中有 19 + 8 (在小盒子中) = 27 个苹果和 20 + 8 (在小盒子中) = 28 个橘子。
大箱子 20 中有 12 + 5 (在小盒子中) = 17 个苹果和 9 + 6 (在小盒子中) = 15 个橘子。
大箱子 8 中有 9 + 5 (在小盒子中) = 14 个苹果和 9 + 6 (在小盒子中) = 15 个橘子。
大箱子 3 中有 16 + 20 (在小盒子中) = 36 个苹果和 7 + 10 (在小盒子中) = 17 个橘子。
苹果的总个数 = 6 + 24 + 27 + 27 + 17 + 14 + 36 = 151
橘子的总个数 = 15 + 25 + 8 + 28 + 15 + 15 + 17 = 123

2.2 思路:

注意到题目是左外连接就简单了。

2.3 题解:

-- 当chest_id为null时,c.apple_count和c.orange_count也就可能为null
with tep as (
    select sum(b.apple_count) + ifNull(c.apple_count, 0) sum1, 
    sum(b.orange_count) + ifNull(c.orange_count, 0) sum2
-- 左外连接,即使不满足连接条件,也仅仅就是不用考虑计算小盒子的情况了
-- 但还要考虑到大盒子的情况
    from Boxes b
    left join Chests c
    on b.chest_id = c.chest_id
    group by box_id
)

select sum(sum1) apple_count,
sum(sum2) orange_count
from tep

3. 力扣1699:两人之间的通话次数

3.1 题目:

表: Calls

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| from_id     | int     |
| to_id       | int     |
| duration    | int     |
+-------------+---------+
该表没有主键(具有唯一值的列),它可能包含重复项。
该表包含 from_id 与 to_id 间的一次电话的时长。
from_id != to_id

编写解决方案,统计每一对用户 (person1, person2) 之间的通话次数和通话总时长,其中 person1 < person2 。

以 任意顺序 返回结果表。

返回结果格式如下示例所示。

示例 1:

输入:
Calls 表:
+---------+-------+----------+
| from_id | to_id | duration |
+---------+-------+----------+
| 1       | 2     | 59       |
| 2       | 1     | 11       |
| 1       | 3     | 20       |
| 3       | 4     | 100      |
| 3       | 4     | 200      |
| 3       | 4     | 200      |
| 4       | 3     | 499      |
+---------+-------+----------+
输出:
+---------+---------+------------+----------------+
| person1 | person2 | call_count | total_duration |
+---------+---------+------------+----------------+
| 1       | 2       | 2          | 70             |
| 1       | 3       | 1          | 20             |
| 3       | 4       | 4          | 999            |
+---------+---------+------------+----------------+
解释:
用户 1 和 2 打过 2 次电话,总时长为 70 (59 + 11)。
用户 1 和 3 打过 1 次电话,总时长为 20。
用户 3 和 4 打过 4 次电话,总时长为 999 (100 + 200 + 200 + 499)。

3.2 思路:

题目很简单,只需要解决怎么处理一会to_id > from_id,一会又反过来的杂乱无章的表。

然后分组解决。

3.3 题解:

-- 优化一下Calls表,为了便于分组,始终保持person1 < person2
with tmp as (
    select duration, if(to_id > from_id, from_id, to_id) person1, 
    if(to_id > from_id, to_id, from_id) person2
    from Calls
)


-- 直接分组,然后计算个数和求和即可。
select person1,person2, count(*) call_count, sum(duration) total_duration
from tmp
group by person1, person2

4. 力扣1445:橘子和苹果

4.1 题目:

表: Sales

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

编写解决方案报告每一天 苹果 和 桔子 销售的数目的差异.

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

返回结果表如下例所示:

示例 1:

输入:
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          |
+------------+------------+-------------+
输出:
+------------+--------------+
| 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).

4.2 思路:

不太会写一行写多个select语句的排版格式,希望有大佬教我啊佬。

4.3题解:

-- 以日期分组,计算出该天的苹果的数量和橘子的数量之差
 select sale_date, 
    (select sum(sold_num) from Sales s1
    where s1.sale_date = s.sale_date and s1.fruit = 'apples')
    - 
    (select sum(sold_num) from Sales s2
    where s2.sale_date = s.sale_date and s2.fruit = 'oranges')
    diff
 from Sales s
 group by sale_date

5. 力扣1495:上月播放的儿童适宜电影

5.1 题目:

表: TVProgram

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| program_date  | date    |
| content_id    | int     |
| channel       | varchar |
+---------------+---------+
(program_date, content_id) 是该表的主键(具有唯一值的列的组合)。
该表包含电视上的节目信息。
content_id 是电视一些频道上的节目的 id。

表: Content

+------------------+---------+
| Column Name      | Type    |
+------------------+---------+
| content_id       | varchar |
| title            | varchar |
| Kids_content     | enum    |
| content_type     | varchar |
+------------------+---------+
content_id 是该表主键(具有唯一值的列)。
Kids_content 是枚举类型, 取值为('Y', 'N'), 其中: 
'Y' 表示儿童适宜内容, 而'N'表示儿童不宜内容。
content_type 表示内容的类型, 比如电影, 电视剧等。

编写解决方案, 报告在 2020 年 6 月份播放的儿童适宜电影的去重电影名.

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

返回结果的格式如下例所示.

示例 1:

输入:
TVProgram 表:
+--------------------+--------------+-------------+
| program_date       | content_id   | channel     |
+--------------------+--------------+-------------+
| 2020-06-10 08:00   | 1            | LC-Channel  |
| 2020-05-11 12:00   | 2            | LC-Channel  |
| 2020-05-12 12:00   | 3            | LC-Channel  |
| 2020-05-13 14:00   | 4            | Disney Ch   |
| 2020-06-18 14:00   | 4            | Disney Ch   |
| 2020-07-15 16:00   | 5            | Disney Ch   |
+--------------------+--------------+-------------+
Content 表:
+------------+----------------+---------------+---------------+
| content_id | title          | Kids_content  | content_type  |
+------------+----------------+---------------+---------------+
| 1          | Leetcode Movie | N             | Movies        |
| 2          | Alg. for Kids  | Y             | Series        |
| 3          | Database Sols  | N             | Series        |
| 4          | Aladdin        | Y             | Movies        |
| 5          | Cinderella     | Y             | Movies        |
+------------+----------------+---------------+---------------+
输出:
+--------------+
| title        |
+--------------+
| Aladdin      |
+--------------+
解释:
"Leetcode Movie" 是儿童不宜的电影.
"Alg. for Kids" 不是电影.
"Database Sols" 不是电影
"Aladin" 是电影, 儿童适宜, 并且在 2020 年 6 月份播放.
"Cinderella" 不在 2020 年 6 月份播放.

5.2 思路:

一步一步翻译题目意思即可。多说一句,with as语句真好用。

5.3 题解:

--  得到2020 年 6 月份播放的记录表
with temp as (
    select *
    from TVProgram 
    where substring(program_date, 1, 7) = '2020-06'
)
-- 记得distinct去重
select distinct title
from temp
join Content c 
on temp.content_id = c.content_id
-- 过滤:适宜电影的去重电影名
where Kids_content = 'Y' and content_type = 'Movies'

6. 力扣1683:无效的推文

6.1 题目:

表:Tweets

+----------------+---------+
| Column Name    | Type    |
+----------------+---------+
| tweet_id       | int     |
| content        | varchar |
+----------------+---------+
在 SQL 中,tweet_id 是这个表的主键。
这个表包含某社交媒体 App 中所有的推文。

查询所有无效推文的编号(ID)。当推文内容中的字符数严格大于 15 时,该推文是无效的。

任意顺序返回结果表。

查询结果格式如下所示:

示例 1:

输入:
Tweets 表:
+----------+----------------------------------+
| tweet_id | content                          |
+----------+----------------------------------+
| 1        | Vote for Biden                   |
| 2        | Let us make America great again! |
+----------+----------------------------------+

输出:
+----------+
| tweet_id |
+----------+
| 2        |
+----------+
解释:
推文 1 的长度 length = 14。该推文是有效的。
推文 2 的长度 length = 32。该推文是无效的。

6.2 思路:

这题素在...

6.3 题解:

select tweet_id
from Tweets 
where length(content) > 15