SQL——子查询
1978上级经历已离职的公司员工
思路
筛选条件:
salary < 30000
:只考虑薪水低于 30000 的员工manager_id is not null
:排除没有经理的员工(确保有明确的管理者)manager_id not in (select employee_id from employees)
:关键条件,筛选出那些管理者 ID 不在公司员工列表中的员工(即他们的管理者不是公司现有员工)
子查询作用:
select employee_id from employees
获取公司所有员工的 ID,用于判断某个管理者是否属于公司内部员工排序:结果按
employee_id
升序排列
这个查询的目的是找出薪水较低且其管理者不属于公司员工的那些员工,可能用于识别一些特殊雇佣关系或异常记录。
SQL语句
# Write your MySQL query statement below
select employee_id from employees as e
where salary<30000 and manager_id is not null and manager_id not in
(select employee_id from employees)
order by employee_id asc
626换座位
思路
基础数据选取
从 seat 表中选取所有座位的 id(记为表 a),作为后续判断和交换的基础。
2. 核心判断逻辑(IF 嵌套)
通过两层 IF 条件,根据座位 id 的奇偶性决定交换规则:
情况 1:当前座位 id 为偶数(a.id%2=0)需与前一个座位(id-1)的学生交换。通过子查询
(select student from seat as b where b.id=a.id-1)
,获取当前座位前一位的学生姓名,作为交换后的结果。情况 2:当前座位 id 为奇数再通过
IFNULL
处理两种子情况:- 若存在下一个座位(id+1 存在):子查询
(select student from seat as c where c.id=a.id+1)
获取后一位学生姓名,完成交换。 - 若不存在下一个座位(当前是最后一个座位):
IFNULL
返回当前座位的原学生姓名(a.student),不进行交换。
- 若存在下一个座位(id+1 存在):子查询
3. 最终结果
返回交换后每个座位的 id,以及对应的学生姓名(命名为 student),实现 “奇数位与偶数位相邻交换,最后一个奇数位不变” 的效果。
SQL语句
# Write your MySQL query statement below
select a.id,if(a.id%2=0,(select student from seat as b where b.id=a.id-1),
ifnull((select student from seat as c where c.id=a.id+1),a.student)) as student
from seat as a
1341电影评分
思路
第一部分查询(用户部分):
- 通过
users
表与movierating
表连接,关联用户和他们的评分记录 - 按用户名
name
分组,统计每个用户的评分次数count(*)
- 先按评分次数降序排序(
order by count(*) desc
),次数相同则按用户名升序排序(name asc
) - 取排名第一的用户,结果列名为
results
- 通过
第二部分查询(电影部分):
- 通过
movies
表与movierating
表连接,关联电影和它们的评分记录 - 限定只考虑 2020 年 2 月的评分(
created_at like '2020-02%'
) - 按电影标题
title
分组,计算每部电影的平均评分avg(rating)
- 先按平均评分降序排序(
order by avg(rating) desc
),评分相同则按标题升序排序(title asc
) - 取排名第一的电影,结果列名为
results
- 通过
结果合并:
- 使用
union all
将两个查询结果合并,最终返回两行数据:第一行是最活跃用户,第二行是 2020 年 2 月最佳电影
- 使用
这个查询适用于需要找出平台上最活跃用户和特定时间段内评分最高电影的场景。
SQL语句
# Write your MySQL query statement below
(select name as results
from users as u join movierating as mr
on u.user_id = mr.user_id
group by name
order by count(*) desc,name asc
limit 1)
union all
(select title as results
from movies as mv join movierating as mr2
on mv.movie_id = mr2.movie_id and created_at like '2020-02%'
group by title
order by avg(rating) desc,title asc
limit 1)
1321餐馆营业额变化增长
思路
子查询筛选有效日期:
- 内部子查询
(SELECT DISTINCT visited_on ...)
筛选出从最早消费日期开始至少第 7 天及之后的所有日期 - 条件
visited_on >= (SELECT MIN(visited_on) FROM customer) + INTERVAL 6 DAY
确保只考虑有完整 7 天消费记录的日期
- 内部子查询
连接与聚合计算:
- 将筛选出的日期表 (t) 与顾客消费表 (c) 连接,关联条件是消费日期在当前日期往前推 6 天的范围内(包含当天)
SUM(c.amount)
计算过去 7 天的总消费金额ROUND(SUM(c.amount)/7, 2)
计算过去 7 天的平均消费金额并保留两位小数
分组与排序:
- 按筛选出的日期 (t.visited_on) 分组,确保每天的 7 天周期数据被正确聚合
- 结果按日期升序排列,展示连续的每日 7 天周期统计
这个查询适用于需要展示 "滚动 7 天消费总额及平均值" 的场景,例如业务分析中追踪每周消费趋势的变化。
SQL语句
SELECT t.visited_on,SUM(c.amount) AS amount,ROUND(SUM(c.amount)/7, 2) AS average_amount
FROM (SELECT DISTINCT visited_on FROM customerWHERE visited_on >= (SELECT MIN(visited_on) FROM customer) + INTERVAL 6 DAY
) t
JOIN customer c
ON c.visited_on BETWEEN t.visited_on - INTERVAL 6 DAY AND t.visited_on
GROUP BY t.visited_on
ORDER BY t.visited_on;
602好友申请
思路
整合用户 ID:
- 子查询通过
union all
将requester_id
(请求者 ID)和accepter_id
(接受者 ID)合并为一个名为ids
的列 - 这样处理是因为无论是请求者还是接受者,在一次成功的好友请求中都算参与,需要统计他们的总出现次数
- 子查询通过
统计与排序:
- 对合并后的
ids
列进行分组(group by id
) - 使用
count(*)
计算每个用户 ID 出现的总次数,命名为num
- 按出现次数降序排序(
order by num desc
),取出现次数最多的用户(limit 1
)
- 对合并后的
这个查询的目的是找出社交网络中在好友关系中最活跃的用户(无论是发起请求还是接受请求),适用于分析平台上的社交活跃用户。
SQL语句
select t1.ids as id,count(*) as num
from(select requester_id as ids from RequestAccepted union allselect accepter_id as ids from RequestAccepted
) as t1
group by id
order by num desc
limit 1;
585.2016年的投资
思路
筛选条件:
- 第一个子查询
(select count(*) from insurance as b where a.tiv_2015 = b.tiv_2015) >= 2
:确保该记录的 2015 年保险金额(tiv_2015)至少在其他一条记录中也出现过(即该 tiv_2015 值不是唯一的)。 - 第二个子查询
(select count(*) from insurance as c where c.lat = a.lat and c.lon = a.lon) = 1
:确保该记录的地理位置(经纬度 lat 和 lon 的组合)是唯一的,没有其他记录在同一位置。
- 第一个子查询
计算总金额:
- 对所有满足上述两个条件的记录,使用
sum(tiv_2016)
计算它们的 2016 年保险金额总和。 - 通过
round(..., 2)
对结果进行四舍五入,保留两位小数,并命名为tiv_2016
。
- 对所有满足上述两个条件的记录,使用
这个查询的目的是筛选出那些具有非唯一 2015 年保险金额但处于唯一地理位置的记录,并计算它们 2016 年的总保险金额,适用于特定的保险数据分析场景。
SQL语句
# Write your MySQL query statement below
select round(sum(tiv_2016),2) as tiv_2016
from insurance as a where (select count(*) from insurance as b where a.tiv_2015=b.tiv_2015)>=2
and (select count(*) from insurance as c where c.lat=a.lat and c.lon=a.lon) =1
186部门工资前三高的所有员工
思路
表关系建立:
- 通过
Employee e1
与Department d
的连接(e1.DepartmentId = d.Id
),将员工与其所属部门关联起来,以便同时获取部门名称和员工信息
- 通过
排名逻辑实现:
- 子查询
(SELECT COUNT(DISTINCT e2.Salary) ...)
的作用是计算 "在同一部门中,薪资高于当前员工 e1 的不同薪资值的数量" - 外部条件
3 > ...
表示:当同一部门中薪资高于当前员工的不同薪资数量小于 3 时,该员工被选中 - 这意味着该员工在本部门的薪资排名为前 3 名(因为最多只有 2 个不同的薪资值比他高)
- 子查询
处理特殊情况:
- 使用
COUNT(DISTINCT e2.Salary)
而非COUNT(e2.Salary)
,是为了正确处理同部门内有多名员工薪资相同的情况 - 例如:如果部门中有 5 名员工,其中 3 人薪资相同且为最高,则这 3 人都会被计入前三
- 使用
这个查询适用于需要找出各部门中薪资水平最高的前三名员工的场景,能够清晰展示部门、员工姓名及其薪资信息。
SQL语句
SELECTd.Name AS 'Department', e1.Name AS 'Employee', e1.Salary
FROMEmployee e1JOINDepartment d ON e1.DepartmentId = d.Id
WHERE3 > (SELECTCOUNT(DISTINCT e2.Salary)FROMEmployee e2WHEREe2.Salary > e1.SalaryAND e1.DepartmentId = e2.DepartmentId)
;