Mysql 刷题 day06
LC 1667
知识点:
本题不难 , 主要学习几个mysql中关于字符串的函数。
1.concat(a , b)将字符串a,b拼接起来
2.upper(str),lower(str)将字符串的每个字母转换为大/小写
3.substring(str ,start ,length) 参数为字符串 ,起始位置(从1开始),截取长度
关键特性
-
起始位置支持负数:
- 若
start_position
为负数,表示从字符串末尾倒数(如-1
表示最后一个字符)。 - 示例:
SUBSTRING("Hello", -3, 2)
→ 返回"ll"
(从倒数第3个字符开始,截取2个字符)。
- 若
-
长度可选:
- 若省略
length
,则截取从start_position
到字符串末尾的所有字符。 - 示例:
SUBSTRING("Hello", 3)
→ 返回"llo"
。
- 若省略
LC 1789 员工的直属部门
方法一:
把仅加入了一个部门的员工查出来 ,把结果再加上 那些有直属部门的员工(即 primary tag = Y)。
使用union合并
关于Union的语法
union:将结果合并 并且 去重。效率低 ,默认去重。
union all : 将两个结果集直接合并 ,不管重不重。
代码如下:
select employee_id , department_id
from Employee
group by employee_id
having count(department_id) = 1union allselect employee_id , department_id
from Employee
where primary_flag = 'Y'
本题坑点:
SELECT employee_id, department_id
FROM Employee
GROUP BY employee_id
HAVING COUNT(department_id) = 1;
在第一条查询语句中 , having语句里的department_id 并没有出现在group by 中 ,也未使用聚合函数(如 MAX
、MIN
)。
标准规则:在严格模式(如 ONLY_FULL_GROUP_BY
)下,SELECT
中的非聚合字段必须满足以下条件之一:
- 包含在
GROUP BY
中。 - 使用聚合函数(如
MAX
、MIN
、ANY_VALUE
)。
SELECT employee_id, department_id -- department_id 未聚合或包含在 GROUP BY
FROM Employee
GROUP BY employee_id
HAVING COUNT(department_id) = 1;
只是leetcode网站上恰好关闭了严格模式 , 实际中通常使用严格模式 , 因为宽松模式可能导致
结果的不确定性:关闭 ONLY_FULL_GROUP_BY 可能导致分组查询返回不确定的结果。特别是当 SELECT 列表中包含非聚合列,且这些列没有包含在 GROUP BY 子句中时,MySQL 将从每个分组中任意选择一个值作为结果,这可能导致结果难以预测和解释。
( 作者:没上岸就继续刷呗
链接:https://leetcode.cn/problems/primary-department-for-each-employee/solutions/2702019/qiang-lie-jian-yi-bu-yao-shi-yong-unionc-l86h/
)
修复方法:
给department_id 加上max或者min , 限制其唯一性 ,让sql语法正确。本题由于通过 HAVING COUNT(department_id) = 1
过滤后,每个分组只剩一个 department_id
,因此 MAX
和 MIN
只能返回该唯一值。但其他情况下 , max 或 min或其他聚合函数可能导致返回值不同 ,要根据题意选择。
方法二:窗口函数
代码:
WITH t AS (SELECTemployee_id,department_id,primary_flag,COUNT(*) OVER(PARTITION BY employee_id) AS count_overFROM Employee)
SELECT employee_id,department_id
FROM t
WHERE count_over = 1 or primary_flag = 'Y'
知识点:
1. with t as (子查询语句) + 主查询语句
在 SQL 中,WITH t AS (...)
是 公共表表达式(Common Table Expression, CTE) 的语法,用于定义一个临时命名的结果集(类似临时表),供后续查询使用。这里的 t
是用户自定义的临时表名称,AS
后面跟随的是生成这个临时表的查询语句。
基本语法:
WITH 临时表名 AS (-- 子查询,定义临时表的数据SELECT ... FROM ...
)
-- 主查询,基于临时表进一步操作
SELECT ... FROM 临时表名;
1. 1窗口函数的作用
窗口函数允许你在不折叠(不合并)原始数据行的前提下,对某个分组(窗口)内的数据进行聚合或分析计算。
与普通聚合函数(如 GROUP BY
)不同,窗口函数不会将多行合并为一行,而是为每一行返回一个基于窗口的计算结果
1.2窗口函数的语法:
函数名([参数]) OVER ([PARTITION BY 字段1, 字段2, ...] -- 定义分组[ORDER BY 字段1 [ASC|DESC], ...] -- 定义排序[ROWS|RANGE 窗口范围] -- 定义窗口范围(可选)
) AS 列别名
2. 语句拆解
COUNT(*) OVER (PARTITION BY employee_id) AS count_over
-
COUNT(*)
:统计行数。 -
OVER
:表示这是一个窗口函数,后续定义窗口范围。 -
PARTITION BY employee_id
:按employee_id
分组,为每个员工单独创建窗口。 -
AS count_over
:将计算结果命名为count_over
。
3. 窗口函数 vs. 普通聚合函数
(1) 普通聚合函数(GROUP BY
)
SELECT employee_id, COUNT(*) AS count_over FROM Employee GROUP BY employee_id;
- 结果:每个员工仅返回一行,包含
employee_id
和对应的部门总数。 - 缺点:丢失了原始数据行的其他列(如
department_id
、primary_flag
)。
(2) 窗口函数
SELECT employee_id,
department_id,
primary_flag,COUNT(*) OVER (PARTITION BY employee_id) AS count_over FROM Employee;
- 结果:保留所有原始列,同时为每个员工的每行数据添加
count_over
列,表示该员工的部门总数。 - 优势:既能分析数据(如统计总数),又无需折叠原始数据。
LC180 连续出现的数字
知识点:
1.窗口函数LAG
语法:LAG(字段, 偏移量)
是一个窗口函数,用于 访问当前行之前(上方)的某行数据。
- 参数:
字段
:要获取的字段名(如num
)。偏移量
:向前查找的行数(如1
表示前一行,2
表示前两行)。
- 默认值:若找不到前 N 行(如首行),返回
NULL
。 - 排序依据:通过
ORDER BY
指定数据行的排列顺序(如ORDER BY id
)。
2.思路
至少连续出现三次:
即对于某行数字来说 ,它既等于该行上一行的数字 , 也等于该行上两行的数据 ,那么这行数字就是第三次出现的数字。
把满足这样条件的数字找出来 ,再distinct一下,即可
select distinct num as ConsecutiveNums
from
(select
num ,
lag(num ,1) over (order by id) as pre1 ,
lag(num ,2) over (order by id) as pre2
from Logs) as temp
where num = temp.pre1 and num = temp.pre2