※食用指南:文章内容为SQL之母网页在线练习笔记及答案,适合完全没学过SQL的朋友们快速学习最基础的知识。
练习传送门: SQL之母 - 免费SQL自学网站 by 程序员鱼皮
如果想更为系统的学习,推荐入门学习视频:
本人的笔记专栏:
MySQL干货笔记(近4万字)------PAULEENHUI
http://t.csdnimg.cn/vouUr
目录:
[20、查询进阶-关联查询-cross join](#20、查询进阶-关联查询-cross join)
11、基础语法-排序
💡 select列1,列2from表名order by列1asc**,列2****desc**
使用 ORDER BY 关键字来实现排序操作。ORDER BY 后面跟上需要排序的字段,可以选择升序(ASC)或降序(DESC)排列。++默认是升序,也可以不用写ASC++
❓ 请编写一条 SQL 查询语句,从名为 student 的数据表中选择出学生姓名(name)、年龄(age)和成绩(score),首先按照成绩从大到小排序,如果成绩相同,则按照年龄从小到大排序。
sql
select name,age,score from student order by score desc,age
❗ 实际工作场景
sql
--物流管理:优先处理高运费且签收早的运单,用于成本分析回溯
select 运单号, 运费金额, 签收日期 from 运单表 order by 运费金额 desc, 签收日期 asc;
--人资数据:查看新员工入职顺序,用于工龄统计和周年关怀
select 姓名, 部门, 入职日期 from 员工表 order by 入职日期 asc;
12、基础语法-截断和偏移
💡 select列1,列2from表名limit****2,2
使用 LIMIT 关键字来实现数据的截断和偏移,典型的应用场景是分页,即网站内容很多时,用户可以根据页号每次只看部分数据。
-- LIMIT 后只跟一个整数,表示要截断的数据条数(一次获取几条)
-- LIMIT 后跟 2 个整数,依次表示从第几条数据开始、一次获取几条
**※**Limit2,2表示从第3条数据的位置开始获取2条数据
❓ 请编写一条 SQL 查询语句,从名为 student 的数据表中选择学生姓名(name)和年龄(age),按照年龄从小到大排序,从第 2 条数据开始、截取 3 个学生的信息。
sql
select name,age from student order by age limit 1,3
❗ 实际工作场景
sql
--财务对账:查看流水记录第10页,每页100条
select 流水号, 交易日期, 金额 from 财务流水表 order by 交易日期 desc limit 900, 100;
--运营分析:查看用户积分排行榜前100,每页20条,第6页会跳过前面100条
select 用户名, 积分 from 用户表 order by 积分 desc limit 100, 20;
13、基础语法-条件分支
💡 select列1,列2case when条件1then结果1when条件2then结果2else其他结果end from****表名
条件分支 case when ,类似于其他编程语言中的 if else 条件判断语句,允许我们根据不同的条件选择不同的结果返回。
使用 case when 可以在查询结果中根据特定的条件动态生成新的列或对现有的列进行转换。
❓ 假设有一个学生表 student,包含以下字段:name(姓名)、age(年龄)。
请你编写一个 SQL 查询,将学生按照年龄划分为三个年龄等级(age_level):60 岁以上为 "老同学",20 岁以上(不包括 60 岁以上)为 "年轻",20 岁及以下、以及没有年龄信息为 "小同学"。
返回结果应包含学生的姓名(name)和年龄等级(age_level),并按姓名升序排序。
sql
select name,
case when age>60 then "老同学" when age>20 then "年轻"
else "小同学" end as age_level
from student order by name asc;
❗ 实际工作场景
sql
--销售报表:根据订单金额划分大、中、小单,用于客户分级运营
select 订单号, 客户名, 金额,
case when 金额 >= 100000 then '大额订单' when 金额 >= 10000 then '中额订单'
else '小额订单' end as 订单层级
from 订单表;
--供应商管理:将供应商评分转化为ABCD等级,用于年度评估报告
select 供应商名称, 综合评分,
case when 综合评分 >= 90 then 'A级-优秀'when 综合评分 >= 75 then 'B级-良好'
when 综合评分 >= 60 then 'C级-合格' else 'D级-不合格'
end as 供应商等级
from 供应商评估表;
14、函数-时间函数
💡 select列1,列2时间函数**()as别名** from****表名
时间函数是用于处理日期和时间的特殊函数。常用的时间函数有:
DATE :获取当前日期
DATETIME :获取当前日期时间
TIME:获取当前时间
-- 获取当前日期:SELECT DATE() AS current_date;
-- 获取当前日期时间:SELECT DATETIME() AS current_datetime;
-- 获取当前时间":SELECT TIME() AS current_time;
其他时间函数,比如计算两个日期的相差天数、获取当前日期对应的毫秒数等,实际运用时自行查阅即可。
❓ 假设有一个学生表 student,包含以下字段:name(姓名)、age(年龄)。请你编写一个 SQL 查询,展示所有学生的姓名(name)和当前日期(列名为 "当前日期")。
sql
select name,date()as "当前日期" from student
❗ 实际工作场景
sql
--货量分析:从快消品门店订单中提取进货年份和月份,用于分析终端补货周期
select 门店名称, 商品名称, 订货量,
year(订货日期) as 订货年份, month(订货日期) as 订货月份 from 门店订货明细表;
--财务对账:根据开票日期和当前日期计算逾期天数,用于催收优先级排序
select 客户名称, 应收金额, datediff(当前日期, 开票日期) as 逾期天数 from 应收账款表;
--运营分析:从注册日期中提取季度,用于季度分析用户增长趋势
select 用户名, 注册日期, quarter(注册日期) as 注册季度 from 用户表;
15、函数-字符串处理
💡 select列1,列2字符函数**()as别名** from****表名
字符串处理是一类用于处理文本数据的函数。如转换大小写、计算字符串长度以及搜索和替换子字符串等。UPPER转为大写、LOW转为小写、LENGTH计算字符串长度
❓ 假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)。请你编写一个 SQL 查询,筛选出姓名为 '热dog' 的学生,展示其学号(id)、姓名(name)及其大写姓名(upper_name)。
sql
select id,name,upper(name) as upper_name from student where name="热dog"
❗ 实际工作场景
sql
--支付系统:银行卡号风控日志或报表展示时强制脱敏
select 交易ID, right(银行卡号, 4) as 卡号后四位 from 支付流水表;
--内容平台:用户搜索词大小写混用,统一小写后存入数仓用于词频统计
select 用户ID, lower(搜索词) as 标准化搜索词 from 搜索日志表;
16、函数-聚合函数
💡 select聚合函数**(列名)** as****别名 from****表名
聚合函数是一类用于对数据集进行**++汇总计算++**的特殊函数。它们可以对一组数据执行诸如计数、求和、平均值、最大值和最小值等操作。聚合函数通常在 SELECT 语句中配合 GROUP BY 子句使用,用于对分组后的数据进行汇总分析。
常见的聚合函数包括:
COUNT:计算指定列的行数或非空值的数量。
SUM:计算指定列的数值之和。
AVG:计算指定列的数值平均值。
MAX:找出指定列的最大值。
MIN:找出指定列的最小值。
❓ 假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、class_id(班级编号)、score(成绩)。请你编写一个 SQL 查询,汇总学生表中所有学生的总成绩(total_score)、平均成绩(avg_score)、最高成绩(max_score)和最低成绩(min_score)。
sql
select SUM(score) as total_score,AVG(score) as avg_score,
MAX(score) as max_score,MIN(score) as min_score from student
❗ 实际工作场景
sql
--支付系统:银行卡号风控日志或报表展示时强制脱敏
select 交易ID, right(银行卡号, 4) as 卡号后四位 from 支付流水表;
--运营数据:对用户行为日志中的用户ID去重计数,计算日活跃用户数
select count(distinct 用户ID) as DAU from 用户行为埋点表 where 日志日期 = 当前日期;
17、分组聚合-单字段分组
💡 select****列名1 /聚合函数(列名2) as****别名 from表名group by****列名1
分组聚合是一种对数据进行分类并对每个分类进行聚合计算的操作。它允许我们按照指定的列或字段对数据进行分组,然后对每个分组应用聚合函数,如 COUNT、SUM、AVG 等,以获得分组后的汇总结果。通常使用++GROUP BY++关键字对数据进行分组。
❓ 假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、class_id(班级编号)、score(成绩)。请你编写一个 SQL 查询,统计学生表中的班级编号(class_id)和每个班级的平均成绩(avg_score)。
sql
select class_id,AVG(score) as avg_score from student group by class_id
❗ 实际工作场景
sql
--风控系统:统计每个用户当天的交易次数,用于反欺诈规则
select 用户ID, count(*) as 交易笔数 from 支付流水表
where 交易日期 = 当前日期 group by 用户ID;
--游戏运营:计算每个服务器所有玩家日活时常,用于评估服务器负载
select 服务器ID, sum(在线时长分钟) as 总在线时长
from 玩家在线日志表 where 日期 = 当前日期 group by 服务器ID;
18、分组聚合-多字段分组
💡 select列名1,列名2聚合函数**(列名3)** as****别名 from表名group by****列名1,列名2
多字段分组和单字段分组的实现方式几乎一致,使用 GROUP BY 语法即可。
❓ 假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、class_id(班级编号)、exam_num(考试编号)、score(成绩)。请你编写一个 SQL 查询,统计学生表中的班级编号(class_id),考试编号(exam_num)和每个班级参加每场考试的总学生人数(total_num)。
sql
select class_id,exam_num,count(*) as total_num
from student group by class_id,exam_num
❗ 实际工作场景
sql
--运营数据:按内容分类和日期分析用户互动情况,用于内容推荐策略调整
select 内容分类, 日期, sum(点赞数 + 评论数 + 分享数) as 总互动量,
avg(互动率) as 平均互动率 from 内容互动日报表
where 日期 between '2026-06-01' and '2026-06-30' group by 内容分类, 日期;
--游戏运营:查看各服务器不同等级区间的玩家付费人数占比,用于调整充值活动策略
select 服务器ID, case when 玩家等级 <= 30 then '新手'
when 玩家等级 <= 60 then '中级' else '高级' end as 等级段,
count(distinct 玩家ID) as 总玩家数,
count(distinct case when 累计充值 > 0 then 玩家ID end) as 付费玩家数
from 玩家信息表 group by 服务器ID,
case when 玩家等级 <= 30 then '新手' when 玩家等级 <= 60 then '中级' else '高级' end;
19、分组聚合-having子句
💡 select****列名1, 聚合函数(列名2) as****别名 from表名group by列名1having聚合函数(别名)
HAVING 子句用于在分组聚合后对分组进行过滤。它允许我们对分组后的结果进行条件筛选,只保留满足特定条件的分组。
※ HAVING 子句与条件查询 WHERE 子句的区别:
WHERE 子句用于在 ++分组之前++ 进行过滤
HAVING 子句用于在 ++分组之后++ 进行过滤
❓ 假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、class_id(班级编号)、score(成绩)。请你编写一个 SQL 查询,统计学生表中班级的总成绩超过 150 分的班级编号(class_id)和总成绩(total_score)。
sql
select class_id,sum(score) as total_score
from student group by class_id having total_score>150
❗ 实际工作场景
sql
--物流管理:找出配送严重超时的渠道&省份,用于整改或更换服务商
select 渠道编码, 省份, avg(配送天数) as 平均时效 from 运单主表
where 发货日期 >= '2026-06-01'group by 渠道编码, 省份having avg(配送天数) > 5;
--广告投放:筛选消耗超过100万且ROI小于1.5的低效渠道,建议关停处理
select 渠道, sum(消耗金额) as 总消耗, sum(转化收入) / sum(消耗金额) as ROI
from 广告投放明细表
where 日期 between '2026-06-01' and '2026-06-30' group by 渠道
having sum(消耗金额) > 1000000 and sum(转化收入) / sum(消耗金额) < 1.5;
--ROI:Return On Investment(投资回报率)
--ROI = (收入 - 成本) / 成本 × 100%
含义:每投入 1 元钱,能赚回多少钱。
· ROI > 1:盈利(投入 1 元,赚回超过 1 元)
· ROI = 1:收支平衡(不赚不亏)
· ROI < 1:亏损(投入 1 元,赚回不到 1 元)
20、查询进阶-关联查询-cross join
💡 select****a.列名1, a.列名2, b.列名3, b.列名4fromA表 across joinB表 b
关联查询是一种用于联合多个数据表中的数据的查询方式,在单张表的基础上,获取更多额外数据。
CROSS JOIN 是一种简单的关联查询,不需要++任何条件++ 来匹配行,它直接将++左表的每一行++ 与++右表的每一行++ 进行组合,返回的结果是++两个表的笛卡尔积++。
※ 通过逗号分隔表名,隐式地实现了笛卡尔积,是 SQL 早期的写法,功能上与 CROSS JOIN 完全相同。
通过给表起别名来简化 SQL 语句:
①employees e表示用e代指employees这个表
②e.emp_name表示employees这个表的emp_name这列数据
|----------|----------|------------|---------|----------------|
| student表 | id(学号) | name(姓名) | age(年龄) | class_id(班级编号) |
| class表 | id(班级编号) | name(班级名称) | / | / |
❓ 请你编写一个 SQL 查询,将学生表和班级表的所有行组合在一起,并返回学生姓名(student_name)、学生年龄(student_age)、班级编号(class_id)以及班级名称(class_name)。
sql
select s.name student_name, s.age student_age,
s.class_id class_id, c.name class_name
from student s cross join class c;
❗ 实际工作场景
sql
--物流管理:对比不同快递渠道在不同重量区间下的运费单价,制定报价策略
select a.渠道名称, b.重量段, a.首重单价 + (b.重量段 - 1) * a.续重单价 as 预估运费
from 渠道运费表 a cross join 重量段配置表 b;
--设备日报:当月每天每台设备的日报初始模板,后需填写实际运行数据
select a.设备编号, b.日期 from 设备信息表 a
cross join (select distinct 日期 from 日历表 where 月份 = 6) b;
------------TBC