LeetCode MySQL练习3(183/626/595/511/620/1873/627)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode MySQL练习3(183/626/595/511/620/1873/627)相关的知识,希望对你有一定的参考价值。

mysql练习3

183. 从不订购的客户

题目描述

某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。

Customers 表:

+----+-------+
| Id | Name  |
+----+-------+
| 1  | Joe   |
| 2  | Henry |
| 3  | Sam   |
| 4  | Max   |
+----+-------+

Orders 表:

+----+------------+
| Id | CustomerId |
+----+------------+
| 1  | 3          |
| 2  | 1          |
+----+------------+

例如给定上述表格,你的查询应返回:

+-----------+
| Customers |
+-----------+
| Henry     |
| Max       |
+-----------+

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/customers-who-never-order
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

先找一样的id,然后输出不在一样id里的id,注意名字可能相同,所以不能用名字

select Name Customers from Customers where Id not in
(select c.Id
from Customers c 
join Orders o 
on o.CustomerId = c.Id);

麻烦了

select Name Customers from Customers where Id not in
(select o.CustomerId
from Orders o);

不用子查询:

SELECT t1.Name Customers 
FROM Customers t1 
LEFT JOIN Orders t2 
ON t1.Id = t2.CustomerId 
WHERE t2.CustomerId is null

626. 换座位

题目描述

小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。

其中纵列的 id 是连续递增的

小美想改变相邻俩学生的座位。

你能不能帮她写一个 SQL query 来输出小美想要的结果呢?

示例:

+---------+---------+
|    id   | student |
+---------+---------+
|    1    | Abbot   |
|    2    | Doris   |
|    3    | Emerson |
|    4    | Green   |
|    5    | Jeames  |
+---------+---------+

假如数据输入的是上表,则输出结果如下:

+---------+---------+
|    id   | student |
+---------+---------+
|    1    | Doris   |
|    2    | Abbot   |
|    3    | Green   |
|    4    | Emerson |
|    5    | Jeames  |
+---------+---------+

注意:

如果学生人数是奇数,则不需要改变最后一个同学的座位。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/exchange-seats
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

稍微一难,就不会了
case when then else end

# 用case when then else end
select (case
        # 当id为奇数,且不是最后一个时
        when id % 2 = 1 and temp.cnt != id then id + 1
        # 当id为奇数,且是最后一个时
        when id % 2 = 1 and temp.cnt = id then id
        # 偶数,减一
        else id - 1
        end
    ) as id, student 
from seat, (select count(*) cnt from seat) as temp
order by id;

if 嵌套if

# 用if嵌套if
select if (id % 2 = 0, id - 1, 
	if(id = (select count(id) from seat), id, id + 1)) as id, student
from seat
order by id;

595. 大的国家

题目描述

这里有张 World 表

+-----------------+------------+------------+--------------+---------------+
| name            | continent  | area       | population   | gdp           |
+-----------------+------------+------------+--------------+---------------+
| Afghanistan     | Asia       | 652230     | 25500100     | 20343000      |
| Albania         | Europe     | 28748      | 2831741      | 12960000      |
| Algeria         | Africa     | 2381741    | 37100000     | 188681000     |
| Andorra         | Europe     | 468        | 78115        | 3712000       |
| Angola          | Africa     | 1246700    | 20609294     | 100990000     |
+-----------------+------------+------------+--------------+---------------+

如果一个国家的面积超过 300 万平方公里,或者人口超过 2500 万,那么这个国家就是大国家。

编写一个 SQL 查询,输出表中所有大国家的名称、人口和面积。

例如,根据上表,我们应该输出:

+--------------+-------------+--------------+
| name         | population  | area         |
+--------------+-------------+--------------+
| Afghanistan  | 25500100    | 652230       |
| Algeria      | 37100000    | 2381741      |
+--------------+-------------+--------------+

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/big-countries
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

select name, population, area from World where area > 3000000 or population > 25000000;

看到评论说到了or和union的区别,主要在于查询效率问题
对于单列来说,用or是没有任何问题的,但是or涉及到多个列的时候,每次select只能选取一个index,如果选择了area,population就需要进行table-scan,即全部扫描一遍,但是使用union就可以解决这个问题,分别使用area和population上面的index进行查询。 但是这里还会有一个问题就是,UNION会对结果进行排序去重,可能会降低一些performance(这有可能是方法一比方法二快的原因),所以最佳的选择应该是两种方法都进行尝试比较。

select name, population, area from World where area > 3000000
union select name, population, area from World where population > 25000000;

511. 游戏玩法分析 I

题目描述

活动表 Activity:

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| player_id    | int     |
| device_id    | int     |
| event_date   | date    |
| games_played | int     |
+--------------+---------+
表的主键是 (player_id, event_date)。
这张表展示了一些游戏玩家在游戏平台上的行为活动。
每行数据记录了一名玩家在退出平台之前,当天使用同一台设备登录平台后打开的游戏的数目(可能是 0 个)。

写一条 SQL 查询语句获取每位玩家 第一次登陆平台的日期。

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

Activity 表:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1         | 2         | 2016-03-01 | 5            |
| 1         | 2         | 2016-05-02 | 6            |
| 2         | 3         | 2017-06-25 | 1            |
| 3         | 1         | 2016-03-02 | 0            |
| 3         | 4         | 2018-07-03 | 5            |
+-----------+-----------+------------+--------------+

Result 表:
+-----------+-------------+
| player_id | first_login |
+-----------+-------------+
| 1         | 2016-03-01  |
| 2         | 2017-06-25  |
| 3         | 2016-03-02  |
+-----------+-------------+

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/game-play-analysis-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

select player_id, min(event_date) first_login from Activity 
group by player_id;

620. 有趣的电影

题目描述

某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述。

作为该电影院的信息部主管,您需要编写一个 SQL查询,找出所有影片描述为非 boring (不无聊) 的并且 id 为奇数 的影片,结果请按等级 rating 排列。

例如,下表 cinema:

+---------+-----------+--------------+-----------+
|   id    | movie     |  description |  rating   |
+---------+-----------+--------------+-----------+
|   1     | War       |   great 3D   |   8.9     |
|   2     | Science   |   fiction    |   8.5     |
|   3     | irish     |   boring     |   6.2     |
|   4     | Ice song  |   Fantacy    |   8.6     |
|   5     | House card|   Interesting|   9.1     |
+---------+-----------+--------------+-----------+

对于上面的例子,则正确的输出是为:

+---------+-----------+--------------+-----------+
|   id    | movie     |  description |  rating   |
+---------+-----------+--------------+-----------+
|   5     | House card|   Interesting|   9.1     |
|   1     | War       |   great 3D   |   8.9     |
+---------+-----------+--------------+-----------+

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/not-boring-movies
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

力扣第二简单的sql题

select id, movie, description, rating from cinema 
where description != 'boring' and id % 2 = 1 
order by rating desc;

不等于推荐用<>,取余mod

select id, movie, description, rating from cinema 
where description <> 'boring' and mod(id, 2) = 1 
order by rating desc;

1873. 计算特殊奖金

题目描述

表: Employees

+-------------+---------+
| 列名        | 类型     |
+-------------+---------+
| employee_id | int     |
| name        | varchar |
| salary      | int     |
+-------------+---------+
employee_id 是这个表的主键。
此表的每一行给出了雇员id ,名字和薪水。

写出一个SQL 查询语句,计算每个雇员的奖金。如果一个雇员的id是奇数并且他的名字不是以’M’开头,那么他的奖金是他工资的100%,否则奖金为0。

Return the result table ordered by employee_id.

返回的结果集请按照employee_id排序。

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

 Employees 表: 
+-------------+---------+--------+
| employee_id | name    | salary |
+-------------+---------+--------+
| 2           | Meir    | 3000   |
| 3           | Michael | 3800   |
| 7           | Addilyn | 7400   |
| 8           | Juan    | 6100   |
| 9           | Kannon  | 7700   |
+-------------+---------+--------+
结果表:
+-------------+-------+
| employee_id | bonus |
+-------------+-------+
| 2           | 0     |
| 3           | 0     |
| 7           | 7400  |
| 8           | 0     |
| 9           | 7700  |
+-------------+-------+

因为雇员id是偶数,所以雇员id 是2和8的两个雇员得到的奖金是0。
雇员id为3的因为他的名字以’M’开头,所以,奖金是0。
其他的雇员得到了百分之百的奖金。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/calculate-special-bonus
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

select employee_id, 
    if(name like 'M%' or mod(employee_id, 2) = 0, 0, salary) as bonus 
from Employees 
order by employee_id;

这样执行效率更高一点

select employee_id, 
    if(name not like 'M%' and mod(employee_id, 2) = 1, salary, 0) as bonus 
from Employees 
order by employee_id;

case when写一手

select employee_id, 
    (case when mod(employee_id, 2) = 1 and name not like 'M%' then salary else 0 end) as bonus
from Employees 
order by employee_id;

或者用substring,(substr也行),但是一般还是用substring,返回name中第一个元素起,长度为1的字符

SELECT employee_id
	, CASE 
		WHEN employee_id % 2 != 1
		OR substring(name, 1, 1) = 'M' THEN 0
		ELSE salary
	END AS bonus
FROM employees

627. 变更性别

题目描述

给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。

注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。

例如:

| id | name | sex | salary |
|----|------|-----|--------|
| 1  | A    | m   | 2500   |
| 2  | B    | f   | 1500   |
| 3  | C    | m   | 5500   |
| 4  | D    | f   | 500    |

运行你所编写的更新语句之后,将会得到以下表:

| id | name | sex | salary |
|----|------|-----|--------|
| 1  | A    | f   | 2500   |
| 2  | B    | m   | 1500   |
| 3  | C    | f   | 5500   |
| 4  | D    | m   | 500    |

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-salary
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

主要是练习update语句,没用过到现在
update 表 set 改变

update salary set sex = case sex when 'm' then 'f' else 'm' end;
update salary set sex = if(sex = 'm', 'f', 'm');

以上是关于LeetCode MySQL练习3(183/626/595/511/620/1873/627)的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 练习<3>

LeetCode-MySQL练习2(180/181/1777/182/196/197/1179)(行转列)(datediff/timestampdiff)

LeetCode-Mysql练习1(175/176/177/178/184/185)(排名函数)

MySQL 练习<1>

MySQL 练习<1>

数据库LeetCode每日练习