力扣高频SQL50题(基础版)重点部分
文章目录
每月交易 I
表:Transactions
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| country | varchar |
| state | enum |
| amount | int |
| trans_date | date |
+---------------+---------+
id 是这个表的主键。
该表包含有关传入事务的信息。
state 列类型为 ["approved", "declined"] 之一。
编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。
以 任意顺序 返回结果表。
查询结果格式如下所示。
示例 1:
<strong>输入:</strong>
Transactions table:
+------+---------+----------+--------+------------+
| id | country | state | amount | trans_date |
+------+---------+----------+--------+------------+
| 121 | US | approved | 1000 | 2018-12-18 |
| 122 | US | declined | 2000 | 2018-12-19 |
| 123 | US | approved | 2000 | 2019-01-01 |
| 124 | DE | approved | 2000 | 2019-01-07 |
+------+---------+----------+--------+------------+
<strong>输出:</strong>
+----------+---------+-------------+----------------+--------------------+-----------------------+
| month | country | trans_count | approved_count | trans_total_amount | approved_total_amount |
+----------+---------+-------------+----------------+--------------------+-----------------------+
| 2018-12 | US | 2 | 1 | 3000 | 1000 |
| 2019-01 | US | 1 | 1 | 2000 | 2000 |
| 2019-01 | DE | 1 | 1 | 2000 | 2000 |
+----------+---------+-------------+----------------+--------------------+-----------------------+
select date_format(trans_date,'%Y-%m') month,country,count(id) trans_count,
count(if(state='approved',1,null)) approved_count,
sum(amount) trans_total_amount,
sum(if(state='approved',amount,0)) approved_total_amount
from Transactions
group by month,country;
select date_format(trans_date,'%Y-%m') month,country,count(id) trans_count,
ifnull(count(case when state='approved' then id end),0) approved_count,
sum(amount) trans_total_amount,
ifnull(sum(case when state='approved' then amount end),0) approved_total_amount
from Transactions
group by month,country;
# 一种是先处理再进行聚合,一种是先聚合统计再处理空值问题
# 注意使用合适的日期函数,还有空值的处理
游戏玩法分析 IV
Table: Activity
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| player_id | int |
| device_id | int |
| event_date | date |
| games_played | int |
+--------------+---------+
(player_id,event_date)是此表的主键(具有唯一值的列的组合)。
这张表显示了某些游戏的玩家的活动情况。
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0)。
编写解决方案,报告在首次登录的第二天再次登录的玩家的 比率,四舍五入到小数点后两位。换句话说,你需要计算从首次登录日期开始至少连续两天登录的玩家的数量,然后除以玩家总数。
结果格式如下所示:
示例 1:
<strong>输入:</strong>
Activity table:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1 | 2 | 2016-03-01 | 5 |
| 1 | 2 | 2016-03-02 | 6 |
| 2 | 3 | 2017-06-25 | 1 |
| 3 | 1 | 2016-03-02 | 0 |
| 3 | 4 | 2018-07-03 | 5 |
+-----------+-----------+------------+--------------+
<strong>输出:</strong>
+-----------+
| fraction |
+-----------+
| 0.33 |
+-----------+
<strong>解释:</strong>
只有 ID 为 1 的玩家在第一天登录后才重新登录,所以答案是 1/3 = 0.33
# 答案
# 连续登录问题 1 定义法 根据用户登录日期排序,取上一行登录日期,和本行的登录日期差为1,即为连续2天登录
select round(count(case when lag_value2 =-1 and datediff(event_date,lag_value1)=1 then player_id end)/count(distinct player_id),2) fraction
from (select player_id,device_id,event_date,
lag(event_date,1,-1) over(partition by player_id order by event_date) lag_value1,
lag(event_date,2,-1) over(partition by player_id order by event_date) lag_value2
from Activity) a ;
# 注意是首次登录,注意这个条件,有的用户可能是首次登录之后,第二天没有登录,但是后面又发生了连续登录两天,这种情况就不符合题意
# 所以要限制lag_value2=-1这个条件,另外lag_value2=-1 and datediff(event_date,lag_value1)=1 限制了
# 首次登录的第二天登录的那条记录,每个用户只有一条数据,不用剔重,不用count(distinct case when lag_value2=-1...)
# 关联join
# 先筛选出每个用户的首次登录时间,根据用户id和登录时间差为1条件进行关联,筛选出不为null的数据
select round(count(case when b.event_date is not null then a.player_id end)/count(a.player_id),2) fraction
from (select player_id,min(event_date) min_date
from Activity group by player_id) a
left join Activity b on a.player_id=b.player_id and datediff(b.event_date,a.min_date)=1;
# 后续补充
select round(count(distinct case when z.rn=1 and date_diff=-1 then player_id end)/count(distinct player_id),2) fraction
from (select a.*,row_number() over(partition by player_id order by event_date) rn,
datediff(event_date,lead(event_date,1,0) over(partition by player_id order by event_date)) date_diff
from activity a) z
销售分析 III
表: Product
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
| unit_price | int |
+--------------+---------+
product_id 是该表的主键(具有唯一值的列)。
该表的每一行显示每个产品的名称和价格。
表:Sales
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| seller_id | int |
| product_id | int |
| buyer_id | int |
| sale_date | date |
| quantity | int |
| price | int |
+------ ------+---------+
这个表可能有重复的行。
product_id 是 Product 表的外键(reference 列)。
该表的每一行包含关于一个销售的一些信息。
编写解决方案,报告 2019年春季
才售出的产品。即仅在2019-01-01至2019-03-31(含)之间出售的商品。
以 任意顺序 返回结果表。
结果格式如下所示。
示例 1:
<strong>输入:</strong>
Product table:
+------------+--------------+------------+
| product_id | product_name | unit_price |
+------------+--------------+------------+
| 1 | S8 | 1000 |
| 2 | G4 | 800 |
| 3 | iPhone | 1400 |
+------------+--------------+------------+
Sales table:
+-----------+------------+----------+------------+----------+-------+
| seller_id | product_id | buyer_id | sale_date | quantity | price |
+-----------+------------+----------+------------+----------+-------+
| 1 | 1 | 1 | 2019-01-21 | 2 | 2000 |
| 1 | 2 | 2 | 2019-02-17 | 1 | 800 |
| 2 | 2 | 3 | 2019-06-02 | 1 | 800 |
| 3 | 3 | 4 | 2019-05-13 | 2 | 2800 |
+-----------+------------+----------+------------+----------+-------+
<strong>输出:</strong>
+-------------+--------------+
| product_id | product_name |
+-------------+--------------+
| 1 | S8 |
+-------------+--------------+
<strong>解释:</strong>
id为1的产品仅在2019年春季销售。
id为2的产品在2019年春季销售,但也在2019年春季之后销售。
id 3的产品在2019年春季之后销售。
我们只退回产品1,因为它是2019年春季才销售的产品。
# 答案
select a.product_id,a.product_name
from Product a
inner join Sales b on a.product_id=b.product_id
group by a.product_id,a.product_name
having max(sale_date) <= '2019-03-31' and min(sale_date) >='2019-01-01';
select product_id,product_name
from Product
where product_id not in (select a.product_id
from Sales a where sale_date > '2019-03-31' or sale_date <'2019-01-01')
and product_id in (select z.product_id from Sales z) ;
# 注意才出售,意思是只有在春季出售,其他时间不出售
连续出现的数字
表:Logs
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| num | varchar |
+-------------+---------+
在 SQL 中,id 是该表的主键。
id 是一个自增列。
找出所有至少连续出现三次的数字。
返回的结果表中的数据可以按 任意顺序 排列。
结果格式如下面的例子所示:
示例 1:
<strong>输入:</strong>
Logs 表:
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
<strong>输出:</strong>
Result 表:
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
<strong>解释:</strong>1 是唯一连续出现至少三次的数字。
# 答案
select num ConsecutiveNums
from (select num,(cast(rn as signed)-id) num_sub
from (select id,num,row_number() over(partition by num order by id) rn
from Logs ) a
group by num,num_sub
having count(1)>=3) b
group by num;
# 定义法
select num ConsecutiveNums
from (select id,num,
lag(num,1,-1) over(order by id) lag_value1,
lag(num,2,-1) over(order by id) lag_value2
from Logs) a
where lag_value1=num and lag_value2=num
group by num;
指定日期的产品价格
产品数据表: Products
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| new_price | int |
| change_date | date |
+---------------+---------+
这张表的主键是 (product_id, change_date)。
这张表的每一行分别记录了 某产品 在某个日期 更改后 的新价格。
写一段 SQL 来查找在 2019-08-16
时全部产品的价格,假设所有产品在修改前的价格都是 10
。
以 任意顺序 返回结果表。
查询结果格式如下例所示。
示例 1:
<strong>输入:</strong>
Products 表:
+------------+-----------+-------------+
| product_id | new_price | change_date |
+------------+-----------+-------------+
| 1 | 20 | 2019-08-14 |
| 2 | 50 | 2019-08-14 |
| 1 | 30 | 2019-08-15 |
| 1 | 35 | 2019-08-16 |
| 2 | 65 | 2019-08-17 |
| 3 | 20 | 2019-08-18 |
+------------+-----------+-------------+
<strong>输出:</strong>
+------------+-------+
| product_id | price |
+------------+-------+
| 2 | 50 |
| 1 | 35 |
| 3 | 10 |
+------------+-------+
# 答案
# 引入辅助列,设置为小于2019-08-16日期的,再进行排名,取小于2019-08-16范围内最大的记录的数据,如果没有则为10
select product_id,if(date_new=0,10,new_price) price
from (select z.*,row_number() over(partition by product_id order by date_new desc) rn
from (select a.*,case when change_date <= '2019-08-16' then change_date else 0 end date_new from Products a) z ) zz
where rn=1;
按分类统计薪水
表: Accounts
+-------------+------+
| 列名 | 类型 |
+-------------+------+
| account_id | int |
| income | int |
+-------------+------+
在 SQL 中,account_id 是这个表的主键。
每一行都包含一个银行帐户的月收入的信息。
查询每个工资类别的银行账户数量。 工资类别如下:
"Low Salary"
:所有工资 严格低于20000
美元。"Average Salary"
: 包含 范围内的所有工资[$20000, $50000]
。"High Salary"
:所有工资 严格大于50000
美元。
结果表 必须 包含所有三个类别。 如果某个类别中没有帐户,则报告 0
。
按 任意顺序 返回结果表。
查询结果格式如下示例。
示例 1:
<strong>输入:</strong>
Accounts 表:
+------------+--------+
| account_id | income |
+------------+--------+
| 3 | 108939 |
| 2 | 12747 |
| 8 | 87709 |
| 6 | 91796 |
+------------+--------+
<strong>输出:</strong>
+----------------+----------------+
| category | accounts_count |
+----------------+----------------+
| Low Salary | 1 |
| Average Salary | 0 |
| High Salary | 3 |
+----------------+----------------+
<strong>解释:</strong>
低薪: 有一个账户 2.
中等薪水: 没有.
高薪: 有三个账户,他们是 3, 6和 8.
# 答案
select 'Low Salary' as category,sum(if(income <20000,1,0)) accounts_count from Accounts
union all
select 'Average Salary' as category,sum(if(income between 20000 and 50000,1,0)) accounts_count from Accounts
union all
select 'High Salary' as category,sum(if(income >50000,1,0)) accounts_count from Accounts;
# 两种思路:1.造出来这三个类别,和表进行关联 2. union all
换座位
表: Seat
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
id 是该表的主键(唯一值)列。
该表的每一行都表示学生的姓名和 ID。
id 是一个连续的增量。
编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的 id 不交换。
按 id
升序 返回结果表。
查询结果格式如下所示。
示例 1:
<strong>输入:</strong>
Seat 表:
+----+---------+
| id | student |
+----+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+----+---------+
<strong>输出:</strong>
+----+---------+
| id | student |
+----+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+----+---------+
<strong>解释:
</strong>请注意,如果学生人数为奇数,则不需要更换最后一名学生的座位。
# 答案
# 奇数+1,偶数-1,最大id为奇数则不变
select id,student
from (select id-1 id,student from Seat where mod(id,2)=0
union
select id+1 id,student from Seat where mod(id,2)=1 and id not in (select max(id) from Seat)
union
select if(mod(id,2)=1,id,id-1) id,student from Seat where id in (select max(id) from Seat)) z order by id;
# lag,lead需要考虑总数据量,注意点是lead(id,1,id)
select id,student
from (select if(mod(id,2)=0,lag(id,1) over(order by id),lead(id,1,id) over(order by id)) id,student from Seat
union
select if(mod(id,2)=0,id-1,id) id,student from Seat where id in (select max(id) from Seat)) z order by id;
# 开窗函数的运用
select id,student
from (select case when mod(id,2)=1 and counts <> id then id+1
when mod(id,2)=1 and counts = id then id
when mod(id,2)<>1 then id-1 end id,student
from Seat,(select max(id) counts from Seat) seat_counts) z
order by id ;
# 注意这种写法
电影评分
表:Movies
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| title | varchar |
+---------------+---------+
movie_id 是这个表的主键(具有唯一值的列)。
title 是电影的名字。
表:Users
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| name | varchar |
+---------------+---------+
user_id 是表的主键(具有唯一值的列)。
表:MovieRating
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| user_id | int |
| rating | int |
| created_at | date |
+---------------+---------+
(movie_id, user_id) 是这个表的主键(具有唯一值的列的组合)。
这个表包含用户在其评论中对电影的评分 rating 。
created_at 是用户的点评日期。
请你编写一个解决方案:
- 查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
- 查找在
February 2020
平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称。
字典序 ,即按字母在字典中出现顺序对字符串排序,字典序较小则意味着排序靠前。
返回结果格式如下例所示。
示例 1:
<strong>输入:</strong>
Movies 表:
+-------------+--------------+
| movie_id | title |
+-------------+--------------+
| 1 | Avengers |
| 2 | Frozen 2 |
| 3 | Joker |
+-------------+--------------+
Users 表:
+-------------+--------------+
| user_id | name |
+-------------+--------------+
| 1 | Daniel |
| 2 | Monica |
| 3 | Maria |
| 4 | James |
+-------------+--------------+
MovieRating 表:
+-------------+--------------+--------------+-------------+
| movie_id | user_id | rating | created_at |
+-------------+--------------+--------------+-------------+
| 1 | 1 | 3 | 2020-01-12 |
| 1 | 2 | 4 | 2020-02-11 |
| 1 | 3 | 2 | 2020-02-12 |
| 1 | 4 | 1 | 2020-01-01 |
| 2 | 1 | 5 | 2020-02-17 |
| 2 | 2 | 2 | 2020-02-01 |
| 2 | 3 | 2 | 2020-03-01 |
| 3 | 1 | 3 | 2020-02-22 |
| 3 | 2 | 4 | 2020-02-25 |
+-------------+--------------+--------------+-------------+
<strong>输出:</strong>
Result 表:
+--------------+
| results |
+--------------+
| Daniel |
| Frozen 2 |
+--------------+
<strong>解释:</strong>
Daniel 和 Monica 都点评了 3 部电影("Avengers", "Frozen 2" 和 "Joker") 但是 Daniel 字典序比较小。
Frozen 2 和 Joker 在 2 月的评分都是 3.5,但是 Frozen 2 的字典序比较小。
# 答案
(select name results
from (select user_id,count(distinct movie_id) cnt
from MovieRating group by user_id) a inner join Users b on a.user_id=b.user_id
order by cnt desc,b.name asc limit 1)
union all
(select b.title
from (select movie_id,avg(rating) avg_score
from MovieRating where substr(created_at,1,7)='2020-02' group by movie_id) a inner join Movies b on a.movie_id=b.movie_id
order by avg_score desc,b.title asc limit 1);
餐馆营业额变化增长
表: Customer
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| name | varchar |
| visited_on | date |
| amount | int |
+---------------+---------+
在 SQL 中,(customer_id, visited_on) 是该表的主键。
该表包含一家餐馆的顾客交易数据。
visited_on 表示 (customer_id) 的顾客在 visited_on 那天访问了餐馆。
amount 是一个顾客某一天的消费总额。
你是餐馆的老板,现在你想分析一下可能的营业额变化增长(每天至少有一位顾客)。
计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值。average_amount
要 保留两位小数。
结果按 visited_on
升序排序。
返回结果格式的例子如下。
示例 1:
<strong>输入:</strong>
Customer 表:
+-------------+--------------+--------------+-------------+
| customer_id | name | visited_on | amount |
+-------------+--------------+--------------+-------------+
| 1 | Jhon | 2019-01-01 | 100 |
| 2 | Daniel | 2019-01-02 | 110 |
| 3 | Jade | 2019-01-03 | 120 |
| 4 | Khaled | 2019-01-04 | 130 |
| 5 | Winston | 2019-01-05 | 110 |
| 6 | Elvis | 2019-01-06 | 140 |
| 7 | Anna | 2019-01-07 | 150 |
| 8 | Maria | 2019-01-08 | 80 |
| 9 | Jaze | 2019-01-09 | 110 |
| 1 | Jhon | 2019-01-10 | 130 |
| 3 | Jade | 2019-01-10 | 150 |
+-------------+--------------+--------------+-------------+
<strong>输出:</strong>
+--------------+--------------+----------------+
| visited_on | amount | average_amount |
+--------------+--------------+----------------+
| 2019-01-07 | 860 | 122.86 |
| 2019-01-08 | 840 | 120 |
| 2019-01-09 | 840 | 120 |
| 2019-01-10 | 1000 | 142.86 |
+--------------+--------------+----------------+
<strong>解释:</strong>
第一个七天消费平均值从 2019-01-01 到 2019-01-07 是restaurant-growth/restaurant-growth/ (100 + 110 + 120 + 130 + 110 + 140 + 150)/7 = 122.86
第二个七天消费平均值从 2019-01-02 到 2019-01-08 是 (110 + 120 + 130 + 110 + 140 + 150 + 80)/7 = 120
第三个七天消费平均值从 2019-01-03 到 2019-01-09 是 (120 + 130 + 110 + 140 + 150 + 80 + 110)/7 = 120
第四个七天消费平均值从 2019-01-04 到 2019-01-10 是 (130 + 110 + 140 + 150 + 80 + 110 + 130 + 150)/7 = 142.86
select visited_on,sum_row amount,round(sum_row/7,2) average_amount
from (select a.*,sum(amount) over(order by visited_on range between interval 6 day preceding and current row) sum_row
from (select visited_on,sum(amount) amount from Customer group by visited_on) a ) z
where date_sub(visited_on,interval 6 day)>=(select min(visited_on) from Customer)
order by visited_on;
# 这里使用range滑动窗口
select visited_on,sum_amt amount,round(sum_amt/7,2) average_amount
from (select a.visited_on,sum(b.amount) sum_amt
from (select distinct visited_on from Customer) a
left join Customer b on b.visited_on between date_sub(a.visited_on,interval 6 day) and a.visited_on
group by a.visited_on) z
having date_sub(visited_on,interval 6 day) >=(select min(visited_on) from Customer)
order by visited_on ;
# 注意a表要进行剔重,要不然(一天中有多条数据的情况下)与b表关联会多算,多一条,算一倍
按日期分组销售产品
表 Activities
:
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| sell_date | date |
| product | varchar |
+-------------+---------+
该表没有主键(具有唯一值的列)。它可能包含重复项。
此表的每一行都包含产品名称和在市场上销售的日期。
编写解决方案找出每个日期、销售的不同产品的数量及其名称。
每个日期的销售产品名称应按词典序排列。
返回按 sell_date
排序的结果表。
结果表结果格式如下例所示。
示例 1:
<strong>输入:</strong>
Activities 表:
+------------+-------------+
| sell_date | product |
+------------+-------------+
| 2020-05-30 | Headphone |
| 2020-06-01 | Pencil |
| 2020-06-02 | Mask |
| 2020-05-30 | Basketball |
| 2020-06-01 | Bible |
| 2020-06-02 | Mask |
| 2020-05-30 | T-Shirt |
+------------+-------------+
<strong>输出:</strong>
+------------+----------+------------------------------+
| sell_date | num_sold | products |
+------------+----------+------------------------------+
| 2020-05-30 | 3 | Basketball,Headphone,T-shirt |
| 2020-06-01 | 2 | Bible,Pencil |
| 2020-06-02 | 1 | Mask |
+------------+----------+------------------------------+
<strong>解释:</strong>
对于2020-05-30,出售的物品是 (Headphone, Basketball, T-shirt),按词典序排列,并用逗号 ',' 分隔。
对于2020-06-01,出售的物品是 (Pencil, Bible),按词典序排列,并用逗号分隔。
对于2020-06-02,出售的物品是 (Mask),只需返回该物品名。
# 答案
# 难点在行转列
select sell_date,count(distinct product) num_sold,group_concat(distinct product separator ',') products
from Activities
group by sell_date
order by sell_date;
查找拥有有效邮箱的用户
表: Users
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| name | varchar |
| mail | varchar |
+---------------+---------+
user_id 是该表的主键(具有唯一值的列)。
该表包含了网站已注册用户的信息。有一些电子邮件是无效的。
编写一个解决方案,以查找具有有效电子邮件的用户。
一个有效的电子邮件具有前缀名称和域,其中:
- 前缀 名称是一个字符串,可以包含字母(大写或小写),数字,下划线
'_'
,点'.'
和/或破折号'-'
。前缀名称 必须 以字母开头。 - 域 为
'``@leetcode.com``'
。
以任何顺序返回结果表。
结果的格式如以下示例所示:
示例 1:
<strong>输入:</strong>
Users 表:
+---------+-----------+-------------------------+
| user_id | name | mail |
+---------+-----------+-------------------------+
| 1 | Winston | winston@leetcode.com |
| 2 | Jonathan | jonathanisgreat |
| 3 | Annabelle | bella-@leetcode.com |
| 4 | Sally | sally.come@leetcode.com |
| 5 | Marwan | quarz#2020@leetcode.com |
| 6 | David | david69@gmail.com |
| 7 | Shapiro | .shapo@leetcode.com |
+---------+-----------+-------------------------+
<strong>输出:</strong>
+---------+-----------+-------------------------+
| user_id | name | mail |
+---------+-----------+-------------------------+
| 1 | Winston | winston@leetcode.com |
| 3 | Annabelle | bella-@leetcode.com |
| 4 | Sally | sally.come@leetcode.com |
+---------+-----------+-------------------------+
<strong>解释:</strong>
用户 2 的电子邮件没有域。
用户 5 的电子邮件带有不允许的 '#' 符号。
用户 6 的电子邮件没有 leetcode 域。
用户 7 的电子邮件以点开头。
# 答案
select user_id, name, mail
from Users
where mail regexp '^[a-zA-Z][a-zA-Z0-9_.-]*\\@leetcode\\.com$';
思路
一般来说,如果你被要求匹配一个字符串,应该最先想到写一个正则表达式模式进行匹配。
正则表达式提供各种功能,以下是一些相关功能:
^:表示一个字符串或行的开头
[a-z]:表示一个字符范围,匹配从 a 到 z 的任何字符。
[0-9]:表示一个字符范围,匹配从 0 到 9 的任何字符。
[a-zA-Z]:这个变量匹配从 a 到 z 或 A 到 Z 的任何字符。请注意,你可以在方括号内指定的字符范围的数量没有限制,您可以添加想要匹配的其他字符或范围。
[^a-z]:这个变量匹配不在 a 到 z 范围内的任何字符。请注意,字符 ^ 用来否定字符范围,它在方括号内的含义与它的方括号外表示开始的含义不同。
[a-z]*:表示一个字符范围,匹配从 a 到 z 的任何字符 0 次或多次。
[a-z]+:表示一个字符范围,匹配从 a 到 z 的任何字符 1 次或多次。
.:匹配任意一个字符。
\.:表示句点字符。请注意,反斜杠用于转义句点字符,因为句点字符在正则表达式中具有特殊含义。还要注意,在许多语言中,你需要转义反斜杠本身,因此需要使用\\.。
$:表示一个字符串或行的结尾。
核心思想是将 name 列的第一个字符从其余字符分开,相应地改变它们的大小写,最后把他们拼回在一起。