高频 SQL 50 题(基础版)| 高级字符串函数 / 正则表达式 / 子句:1667. 修复表中的名字、1527. 患某种疾病的患者、196. 删除重复的电子邮箱、176. 第二高的薪水、...
高级字符串函数 / 正则表达式 / 子句
1667. 修复表中的名字
题目链接:1667. 修复表中的名字
状态:学会了
思路:
要求修复名字(首字母大写,其他字母小写),按顺序返回。
想法就是取出名字这一列,把第一个字母与其他字符分开,分别对应修改大小写,然后连在一起。
高级字符串函数:
SUBSTRING(column_name, start, length)
:这将从列的值中提取一个子字符串,从指定的起始位置开始,直到指定的长度。
UPPER(expression)
:这会将字符串表达式转换为大写。
LOWER(expression)
:这会将字符串表达式转换为小写。
CONCAT(string1, string2, ...)
:这会将两个或多个字符串连接成一个字符串。
select
user_id,
concat(upper(substring(name, 1, 1)), lower(substring(name, 2)))as name
from Users
order by user_id;
1527. 患某种疾病的患者
题目链接:1527. 患某种疾病的患者
状态:学会了
思路:
需要查询患I类糖尿病的信息返回。
用 like
简单模式匹配字符,通配符只有%
(代表任意数量的任意字符)和 _
(代表单个任意字符)。这个问题可以归结于两种情况:1.条件代码以"DIABI"开头和2.条件代码包含" DIABI".
select patient_id, patient_name, conditions
from Patients
where conditions like "% DIAB1%" or conditions like "DIAB1%";
196. 删除重复的电子邮箱
题目链接:196. 删除重复的电子邮箱
状态:学会了
思路:
要求删除所有重复的电子邮件(保留id最小的一个)。
1.使用自连接 join
,找到哪些记录是重复的:email字段字段相同,但是id不同的记录组合。
2.执行删除条件 delete
,delete p1
表示我们要删除p1
表中满足连接条件的那些行。
delete p1
from Person p1
join Person p2
on p1.email=p2.email and p1.id>p2.id;
176. 第二高的薪水
题目链接:176. 第二高的薪水
状态:学会了
思路:
要找到第二高的不同的薪水,若不存在返回NULL。
第一反应肯定是用到ifnull函数,如salary不存在直接返回null。这是我写的第一版的代码,有一个问题是:当不存在rank_sal=2,表是个空的,infull没有读取到任何salary的值,所以没有东西替换,直接就错了。
select ifnull(salary, NULL) as SecondHighestSalary
from (
select salary, (dense_rank() over(order by salary desc)) as rank_sal
from Employee
) a
where rank_sal=2
反思了一下这个写法,觉得应该把查询salary整个部分的做成子查询,放进infull里面。这样当不存在rank_sal=2,子查询返回的结果是null,所以ifnull返回null。
select (
ifnull (
(
select distinct salary
from (
select salary, (dense_rank() over(order by salary desc)) as rank_sal
from Employee
) a
where rank_sal=2
)
, NULL
)
) as SecondHighestSalary
1484. 按日期分组销售产品
题目链接:1484. 按日期分组销售产品
状态:学会了
思路:
找出每个日期(排序)、销售的不同产品的数量及名称(按字典排序)。
1.对日期进行分组,然后用count distinct统计分组的物品数量。
2.对每个组中唯一名称进行排序和连接,使用的是group_concat()
函数,将分组中的多行的多个值组合成一个字符串。
3.对最后结果的日期进行升序排序。
select
sell_date,
count(distinct product) as num_sold,
group_concat(distinct product order by product separator ',') as products
from Activities
group by sell_date
order by sell_date;
MySQL中GROUP_CONCAT
函数语法:
GROUP_CONCAT(
DISTINCT expression1
ORDER BY expression2
SEPARATOR sep
);
1327. 列出指定时间段内所有的下单产品
题目链接:1327. 列出指定时间段内所有的下单产品
状态:自己写出来的
思路:
要求在2020年2月份下单数量不少于100的产品的名字和数目。
1.内层子查询:筛选orders表中日期在2020年2月份的,按照产品id分类,计算产品的累计销售数目。
2.外层查询:筛选累计销售数目大于等于100的,products表左连接子查询结果,通过on p.product_id=o.product_id关联,返回名字和累计销售数目。
select p.product_name, o.sum_unit as unit
from Products p
left join (
select product_id, sum(unit) as sum_unit
from Orders
where date_format(order_date, "%Y-%m")='2020-02'
group by product_id
) o on p.product_id=o.product_id
where o.sum_unit>=100
1517. 查找拥有有效邮箱的用户
题目链接:1517. 查找拥有有效邮箱的用户
状态:学会了
思路:
要求返回符合要求的:必须 以字母开头,剩下可以包含字母(大写或小写),数字,下划线 ‘_’ ,点 ‘.’ 和/或破折号 ‘-’ ,最后必须为 ‘@leetcode.com’ 。
以任何顺序返回结果表。
正则表达式 regexp
, 就是 regular expression 正则表达式 的意思:
^
表示以后面的字符为开头
[]
表示括号内任意字符
-
表示连续
*
表示重复前面任意字符任意次数
\
用来转义后面的特殊字符,以表示字符原本的样子,而不是将其作为特殊字符使用
$
表示以前面的字符为结尾
正则表达式里有一些字符被赋予了特殊意义,用于表示特定的匹配规则,若要匹配这些字符本身,就需要使用转义字符 \。常见的具有特殊含义的字符如下:
元字符:像 .、*、+、?、^、$、(、)、[、]、{、}、|
等。
特定的转义序列:\d
代表任意数字,\s
代表任意空白字符,\w
代表任意字母、数字或下划线。
select *
from Users
where mail regexp '^[a-zA-Z][a-zA-Z\_\.\-]+@leetcode\.com$';
一点不着边际的话
这是第一遍刷,实在是很难判断出来什么时候用left join,什么时候join,什么时候inner join,什么时候用子查询,还有MySQL这一大把的奇妙小函数,目前还需要记住关于日期和处理字符串的。