5. 牛客网数据(二)(SQL72~NC83)
SQL72 考试分数(一)
请你写一个sql语句查询各个岗位分数的平均数,并且按照分数降序排序,结果保留小数点后面3位 (3位之后四舍五入)
SELECT
job,
ROUND(AVG(score), 3) AS avg
FROM grade
GROUP BY job
ORDER BY avg DESC;SQL73 考试分数(二)
请你写一个sql语句查询用户分数大于其所在工作(job)分数的平均分的所有grade的属性,并且以id的升序排序
法1. 窗口函数
因为窗口函数一般用在 SELECT 中而不能直接用在 WHERE 中,又因为 SELECT 执行顺序在 WHERE 之后,所以如果要用 WHERE 对窗口函数进行筛选就必须再嵌套一层查询
SELECT id, job, score
FROM(
SELECT
*,
AVG(score) OVER(PARTITION BY job) AS avg
FROM grade
) AS grade_new
WHERE score > avg
ORDER BY id;法2. 子查询
因为子查询可以直接用在 WHERE 中构造筛选条件,所以对这道题来说,子查询写起来还简便一点(不过执行效率会低很多(虽然实验中发现区别并不大))
SELECT *
FROM grade g
WHERE score > (SELECT AVG(score)
FROM grade
WHERE job = g.job)
ORDER BY id;SQL74 考试分数(三)
请你找出每个岗位分数排名前2的用户,得到的结果先按照language的name升序排序,再按照积分降序排序,最后按照grade的id升序排序
法1. 窗口函数
SELECT g1.id,l.name,g1.score
FROM(
SELECT *,
DENSE_RANK() OVER(PARTITION BY language_id ORDER BY score DESC) AS r
FROM grade g
) g1
JOIN language l
ON g1.language_id=l.id
WHERE r<=2
ORDER BY l.name, g1.score DESC, g1.id法2. 子查询
SELECT
g.id,
name,
score
FROM grade g
JOIN language l
ON g.language_id = l.id
WHERE (
-- 1. 中式排名 = 比他高的【不同的】分数的个数 + 1:
SELECT COUNT(DISTINCT score) + 1
FROM grade
WHERE language_id = g.language_id
AND score > g.score
) <= 2 -- 2. 筛选排名前 2 名的
ORDER BY name, score DESC, id;SQL75 考试分数(四)
请你写一个sql语句查询各个岗位分数升序排列之后的中位数位置的范围,并且按job升序排序
SELECT job,
(CASE WHEN count(*)%2=0 THEN ROUND(count(*)/2)
ELSE ROUND((count(*)+1)/2) END
) AS start,
(CASE WHEN count(*)%2=0 THEN ROUND(count(*)/2+1)
ELSE ROUND((count(*)+1)/2) END
) AS end
FROM grade
GROUP BY job
ORDER BY job看了评论区,发现直接用ROUND()就可以解决。ROUND(x):返回参数X的四舍五入的一个整数
select a.job, round(count(a.id)/2), round((count(a.id)+1)/2) from grade a group by a.job order by job
SQL76 考试分数(五)
请你写一个sql语句查询各个岗位分数的中位数位置上的所有grade信息,并且按id升序排序
要得到每个岗位位于中位数位置的一个或两个成绩,思路如下:
1.为了下一步的筛选,构造两个辅助列,分别计算岗位内排名(为了得到中位数,应该用 ROW_NUMBER() )和岗位内候选人数
2.选取中位数:若岗位内候选人数为奇数,就选取排名中间的一位,若是偶数,就选取中间的两位
WITH grade_new AS(
SELECT
id,
job,
score,
# 1. 构造两个辅助列,分别计算岗位内排名和岗位内候选人数:
ROW_NUMBER() OVER(PARTITION BY job ORDER BY score DESC) AS t_rank,
-- 以找中位数为目的,这里用 ROW_NUMBER() 比用 RANK() 或 DENSE_RANK() 更合适
-- 注:ROW_NUMBER() 好像很难用子查询替换
COUNT(id) OVER(PARTITION BY job) AS ct
FROM grade
)
SELECT
id,
job,
score,
t_rank
FROM grade_new
WHERE
/* 2. 筛选中位数:
若岗位内候选人数为奇数,就选取排名中间的一位;
若是偶数,就选取中间的两位 */
CASE
WHEN ct % 2 = 1 THEN t_rank = ct DIV 2 + 1
ELSE t_rank = ct / 2 OR t_rank = ct / 2 + 1
END
ORDER BY id;SQL77 牛客的课程订单分析(一)
请你写出一个sql语句查询在2025-10-15以后状态为购买成功的C++课程或者Java课程或者Python的订单,并且按照order_info的id升序排序
SELECT *
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
ORDER BY id;SQL78 牛客的课程订单分析(二)
写出一个sql语句查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的user_id,并且按照user_id升序排序
SELECT user_id
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY user_id
HAVING COUNT(id) >= 2
ORDER BY user_id;SQL79 牛客的课程订单分析(三)
请你写出一个sql语句查询在2025-10-15以后,同一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程的订单信息,并且按照order_info的id升序排序
法1:窗口函数
select t1.id, t1.user_id,t1.product_name,t1.status,t1.client_id,t1.date
from
(
select *,count(id) over(partition by user_id) as number
from order_info
where datediff(date,"2025-10-15")>0
and status ="completed"
and product_name in ("C++","Java","Python")
) t1
where t1.number >1
order by t1.id法2:子查询
SELECT *
FROM order_info
WHERE user_id IN (
SELECT user_id
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY user_id
HAVING COUNT(id) >= 2
)
AND date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
ORDER BY id;SQL80 牛客的课程订单分析(四)
请你写出一个sql语句查询在2025-10-15以后,如果有一个用户下单2个以及2个以上状态为购买成功的C++课程或Java课程或Python课程,那么输出这个用户的user_id,以及满足前面条件的第一次购买成功的C++课程或Java课程或Python课程的日期first_buy_date,以及购买成功的C++课程或Java课程或Python课程的次数cnt,并且输出结果按照user_id升序排序
SELECT
user_id,
MIN(date) AS first_buy_date,
COUNT(id) AS cnt
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY user_id
HAVING COUNT(id) >= 2
ORDER BY user_id;注意,用 GROUP BY 分组后确实可以用窗口函数,但这时窗口函数是基于整个 GROUP BY分组之后的查询结果而不是基于每组组内的查询结果。比如,想求一共分为了多少个组:SELECT COUNT() OVER() FROM ………… GROUP BY …… LIMIT 1;,如果不用窗口函数,就要在外面再嵌套一层查询用 COUNT() 来求分为了多少组。
??SQL81 牛客的课程订单分析(五)
法一:窗口函数
select
a.user_id,
max(case when a.rank_no=1 then a.date else 0 end) as first_buy_date,
max(case when a.rank_no=2 then a.date else 0 end) as second_buy_date,
a.cnt
from
(select
user_id,
date,
row_number() over(partition by user_id order by date) as rank_no,
count(*) over(partition by user_id) as cnt
from order_info
where date >= '2025-10-16'
and status = 'completed'
and product_name in('C++','Java','Python')
) a
where a.rank_no<=2 and a.cnt>=2
group by a.user_id,a.cnt
order by a.user_id ;为什么CASE前加MIN没懂?
法二:子查询+limit
WITH order_new AS(
SELECT *
FROM order_info o
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
)
SELECT
user_id,
MIN(date) AS first_buy_date,
(SELECT date
FROM order_new
WHERE user_id = o.user_id
ORDER BY date
LIMIT 1, 1) AS second_buy_date,
COUNT(id) AS cnt
FROM order_new o
GROUP BY user_id
HAVING COUNT(id) >= 2
ORDER BY user_id;NC82 牛客的课程订单分析(六)
法一:窗口函数
select t.id,t.is_group_buy,c.name
from
(select *, count(*) over(partition by user_id) as cnt
from order_info
where date>'2025-10-15'
and product_name in ('C++','Java','Python')
and status='completed') t
left join client c on t.client_id=c.id
where t.cnt>=2
order by t.id法二:子查询
SELECT o.id, is_group_buy,
(CASE WHEN is_group_buy='YES' THEN 'None' ELSE c.name END) AS client_name
FROM order_info o
LEFT JOIN client c
ON o.client_id=c.id
WHERE user_id IN (
SELECT user_id
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY user_id
HAVING COUNT(id) >= 2
)
AND date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
ORDER BY o.idNC83 牛客的课程订单分析(七)
法一:窗口函数
SELECT
(CASE WHEN is_group_buy='Yes' THEN 'GroupBuy'
ELSE c.name END) AS source,
COUNT(*) cnt
FROM (
SELECT *,
COUNT(*) OVER(PARTITION BY user_id) ct
FROM order_info
WHERE date > '2025-10-15'
and product_name in ('C++', 'Python', 'Java')
and status = 'completed'
) o
LEFT JOIN client c ON o.client_id=c.id
WHERE ct>=2
GROUP BY source
ORDER BY source法二:子查询
SELECT
(CASE WHEN is_group_buy='Yes' THEN 'GroupBuy'
ELSE c.name END) AS source,
COUNT(*)
FROM order_info o
LEFT JOIN client c
ON o.client_id=c.id
WHERE user_id IN (
SELECT user_id
FROM order_info
WHERE date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY user_id
HAVING COUNT(id) >= 2
)
AND date > '2025-10-15'
AND product_name IN ('C++', 'Java', 'Python')
AND status = 'completed'
GROUP BY client_id
ORDER BY source
查看17道真题和解析