我昨天码的《269条常用SQL查询语句》,有的朋友觉得单单常用SQL查询语句这一块,基础的,咋就有这么多?我4年前SQL入门的时候,刚开始看到老师的PPT是这样的:
SELECT [DISTINCT] [TOP] 字段名
FROM 表名
[WHERE] 条件筛选
[GROUP BY] 分组
[HAVING] 分组筛选
[ORDER BY] 排序
当时我觉得,大数据!原来也没什么吗?后来,有一段时间,我与前面朋友的感觉是一样的。为了破解这一感觉,下面,我们一起来把我昨天码的《269条常用SQL查询语句》缩编成《10类SQL查询语句语法结构模板》,这样,只要记住了这些模板,就知道大部分SQL查询语句了,要直接记忆的SQL查询语句就少了。需要的时候,无论是简单的数据筛选,还是复杂的层级统计,我们都可根据这些模板来写或组合SQL查询语句快速实现功能。(三点说明,敬请谅解:稿子是赶出来的,需说明的SQL细节或冗余没时间备注或优化,有问题,留言区讨论;所有代码块或表格,均可左右滚动;用Markdown码的字,纯文本md文档不提供下载,后面有机会转成PDF提供下载。)
一、基础查询(单表简单查询)
从单个表中查询数据,不涉及复杂逻辑。
-- 基础查询语法
SELECT [DISTINCT | ALL] -- DISTINCT去重,ALL保留所有(默认)
列名1 [AS 别名1], -- 要查询的列,AS可指定别名
列名2 [AS 别名2],
...
[表达式] -- 如:计算列:price * 1.1 AS 含税价格
FROM 表名 [AS 表别名] -- 指定数据来源表,AS可省略
[WHERE 行过滤条件] -- 可选,筛选符合条件的行(不能用聚合函数)
[ORDER BY 排序列 [ASC | DESC], ...] -- 可选,按指定列排序(ASC升序,DESC降序)
[LIMIT 行数] -- 可选,限制返回的行数(部分数据库用TOP、ROWNUM等)
示例:从students
表中查询年龄大于18的学生姓名和学号,并按学号升序排列,最多返回10条。
SELECT student_id AS 学号, name AS 姓名
FROM students
WHERE age > 18
ORDER BY student_id ASC
LIMIT 10;
二、多表连接查询
从多个相关表中联合查询数据,通过连接条件关联表之间的关系。
-- 多表连接查询语法
SELECT 表1.列1, 表2.列2, ... -- 需指定列所属表(或用别名简化)
FROM 表1 [AS 别名1]
[INNER | LEFT | RIGHT | FULL] JOIN 表2 [AS 别名2] -- 连接类型
ON 连接条件 -- 定义两表的关联关系(如:表1.id = 表2.关联id)
[JOIN 表3 [AS 别名3] ON 连接条件 ...] -- 可继续连接更多表
[WHERE 行过滤条件] -- 筛选连接后的行
[ORDER BY 排序列 ...] -- 排序结果
连接类型说明:
INNER JOIN
:只保留两表中匹配连接条件的行;LEFT JOIN
:保留左表所有行,右表无匹配则补NULL;RIGHT JOIN
:保留右表所有行,左表无匹配则补NULL;FULL JOIN
:保留两表所有行,无匹配则补NULL(部分数据库不支持)。
示例:查询学生姓名及对应的班级名称(关联students
表和classes
表)。
SELECT s.name AS 学生姓名, c.class_name AS 班级名称
FROM students AS s
LEFT JOIN classes AS c
ON s.class_id = c.class_id; -- 连接条件:学生表的班级id = 班级表的id
三、聚合查询(带GROUP BY)
对数据进行分组统计(如:求和、平均值等),需结合聚合函数(SUM、AVG、COUNT等)。
-- 聚合查询语法
SELECT
分组列1 [AS 别名1], -- 按该列分组(必须出现在GROUP BY中)
分组列2 [AS 别名2],
聚合函数(列) [AS 聚合别名] -- 如:COUNT(*) AS 总数,SUM(score) AS 总分
FROM 表名
[WHERE 行过滤条件] -- 先筛选行,再分组(不能用聚合函数)
GROUP BY 分组列1, 分组列2, ... -- 按指定列分组
[HAVING 分组过滤条件] -- 可选,筛选分组后的结果(可使用聚合函数)
[ORDER BY 排序列 ...] -- 排序分组结果
示例:统计每个班级的学生人数,只保留人数大于30的班级。
SELECT class_id AS 班级ID, COUNT(*) AS 学生人数
FROM students
WHERE age >= 18 -- 先筛选18岁以上的学生
GROUP BY class_id -- 按班级分组
HAVING COUNT(*) > 30 -- 筛选人数超30的班级
ORDER BY 学生人数 DESC;
四、窗口函数查询
在“窗口”(一组与当前行相关的行)中执行计算,不改变原表行数,排名、分组内统计等场景常用。
-- 窗口函数查询语法
SELECT
普通列, -- 常规查询列
窗口函数(列) OVER ( -- 窗口函数+OVER子句定义窗口
[PARTITION BY 分组列] -- 可选:按列分组(类似GROUP BY,但不合并行)
[ORDER BY 排序列 [ASC|DESC]] -- 可选:组内排序
[ROWS|RANGE BETWEEN 窗口范围] -- 可选:定义窗口大小(如:前3行到当前行)
) AS 窗口结果别名
FROM 表名
[WHERE 行过滤条件] -- 筛选行
[其他子句,如:GROUP BY、ORDER BY等]
常用窗口函数:
- 排名函数:RANK()(跳号排名)、DENSE_RANK()(连续排名)、ROW_NUMBER()(行号);
- 聚合函数:SUM()、AVG()等(在窗口内计算)。
示例:查询每个班级学生的成绩及该班级的平均分(不合并原学生行)。
SELECT
student_id AS 学号,
class_id AS 班级ID,
score AS 成绩,
AVG(score) OVER (PARTITION BY class_id) AS 班级平均分 -- 按班级分组计算平均分
FROM scores;
五、子查询(嵌套查询)
将一个查询作为另一个查询的一部分(如:条件、数据源等),用在复杂逻辑拆分。
-- 子查询常见位置示例(以WHERE子句为例)
SELECT 列名
FROM 表名
WHERE 列名 运算符 ( -- 子查询作为条件
SELECT 列名 FROM 子表 WHERE 子查询条件
);
-- 子查询也可作为数据源(FROM子句中)
SELECT t.列名
FROM (SELECT 列名 FROM 表名 WHERE 条件) AS t -- 子查询结果作为临时表t
WHERE t.列名 > 100;
示例:查询成绩高于班级平均分的学生(子查询计算平均分)。
SELECT student_id, score
FROM scores s1
WHERE score > (
SELECT AVG(score) FROM scores s2 WHERE s1.class_id = s2.class_id -- 子查询:当前学生所在班级的平均分
);
六、联合查询(UNION/UNION ALL)
将多个查询结果集合并为一个结果集,要求各查询的列数、列类型一致。
-- 联合查询语法
查询语句1 -- 第一个查询结果集
[UNION | UNION ALL] -- 合并方式
查询语句2 -- 第二个查询结果集
[UNION | UNION ALL]
... -- 可继续合并更多查询结果集
[ORDER BY 排序列 ...] -- 对合并后的整体结果排序(需写在最后)
合并方式说明:
UNION
:合并结果集并去除重复行(会进行去重操作,效率较低);UNION ALL
:直接合并所有行,包括重复行(不进行去重,效率较高)。
示例:查询所有年龄小于18岁的学生和所有年龄大于60岁的教师,合并结果并按姓名排序。
-- 查询学生表中年龄小于18岁的学生
SELECT name AS 姓名, '学生' AS 身份, age AS 年龄 FROM students WHERE age < 18
UNION ALL
-- 查询教师表中年龄大于60岁的教师
SELECT name AS 姓名, '教师' AS 身份, age AS 年龄 FROM teachers WHERE age > 60
ORDER BY 姓名 ASC; -- 对合并后的结果按姓名升序排列
七、带条件的聚合与行转列查询
在聚合查询中按不同条件分别统计,可在一次查询中同时统计同一分组下不同条件的数据,避免多次查询后手动合并结果,或实现行数据到列数据的转换(如:交叉表),常结合CASE WHEN
语句使用。
-- 带条件的聚合查询语法
SELECT
分组列, -- 按该列分组
-- 按条件统计不同类别的数量/总和等
SUM(CASE WHEN 条件1 THEN 列名 ELSE 0 END) AS 统计结果1,
AVG(CASE WHEN 条件2 THEN 列名 ELSE NULL END) AS 统计结果2,
...
FROM 表名
GROUP BY 分组列 -- 按指定列分组
[ORDER BY 分组列 ...]
示例:统计每个班级中男生和女生的人数(行转列效果)。
SELECT
class_id AS 班级ID,
-- 统计男生人数:当性别为男时计数1,否则0,再求和
SUM(CASE WHEN gender = '男' THEN 1 ELSE 0 END) AS 男生人数,
-- 统计女生人数:当性别为女时计数1,否则0,再求和
SUM(CASE WHEN gender = '女' THEN 1 ELSE 0 END) AS 女生人数
FROM students
GROUP BY class_id -- 按班级分组统计
ORDER BY class_id;
八、递归查询(WITH RECURSIVE)
处理具有递归关系的数据(如:树形结构:部门层级、评论回复等),通过递归迭代获取多层关联数据,高效处理层级嵌套数据,无需我们手动多层关联查询。
-- 递归查询语法(以PostgreSQL为例,MySQL 8.0+也支持)
WITH RECURSIVE 递归表名 (列1, 列2, ...) AS (
-- 1. 初始查询(锚点成员):获取最顶层数据
SELECT 列1, 列2, ...
FROM 表名
WHERE 初始条件 -- 如:父节点ID为NULL(顶层节点)
UNION ALL
-- 2. 递归查询(递归成员):关联自身获取下一层数据
SELECT 子表.列1, 子表.列2, ...
FROM 表名 AS 子表
INNER JOIN 递归表名 AS 父表
ON 子表.父节点列 = 父表.当前节点列 -- 子节点关联父节点
)
-- 3. 查询递归结果
SELECT * FROM 递归表名 [ORDER BY 排序条件];
示例:查询公司部门的层级结构(departments
表含dept_id
、dept_name
、parent_dept_id
)。
WITH RECURSIVE dept_hierarchy (dept_id, dept_name, parent_dept_id, level) AS (
-- 初始查询:获取顶级部门(无父部门,parent_dept_id为NULL),层级设为1
SELECT dept_id, dept_name, parent_dept_id, 1 AS level
FROM departments
WHERE parent_dept_id IS NULL
UNION ALL
-- 递归查询:关联子部门,层级+1
SELECT d.dept_id, d.dept_name, d.parent_dept_id, dh.level + 1 AS level
FROM departments AS d
INNER JOIN dept_hierarchy AS dh
ON d.parent_dept_id = dh.dept_id -- 子部门的父ID = 递归表中的部门ID
)
-- 查询所有部门及层级,按层级和部门ID排序
SELECT dept_id, dept_name, parent_dept_id, level
FROM dept_hierarchy
ORDER BY level, dept_id;
九、CTE查询(公用表表达式,WITH子句)
通过WITH
子句定义一个临时结果集(CTE),替代子查询或临时表,使查询结构更清晰,尤其适用于需多次复用同一子查询结果的场景,可在后续查询中多次引用,简化复杂查询的逻辑结构。
-- CTE查询语法
WITH cte_name1 (列1, 列2, ...) AS ( -- 定义第一个CTE
SELECT 列1, 列2, ... FROM 表名 WHERE 条件
),
cte_name2 (列a, 列b, ...) AS ( -- 定义第二个CTE(可多个,用逗号分隔)
SELECT 列a, 列b, ... FROM cte_name1 WHERE 条件 -- 可引用已定义的CTE
)
-- 主查询:使用CTE
SELECT * FROM cte_name1
INNER JOIN cte_name2 ON 关联条件;
示例:先筛选出成绩前50%的学生,再统计这些学生的班级分布。
-- 定义CTE:筛选成绩前50%的学生(假设用ROW_NUMBER和总人数计算)
WITH top_half_students AS (
SELECT
student_id,
class_id,
score,
-- 计算当前学生在所有学生中的排名(降序)
ROW_NUMBER() OVER (ORDER BY score DESC) AS score_rank,
-- 计算学生总人数
COUNT(*) OVER () AS total_students
FROM scores
-- 筛选排名 <= 总人数的50%(即前50%)
QUALIFY score_rank <= total_students * 0.5 -- QUALIFY用于筛选窗口函数结果(部分数据库支持)
)
-- 主查询:统计前50%学生的班级分布
SELECT class_id AS 班级ID, COUNT(*) AS 前50%学生人数
FROM top_half_students
GROUP BY class_id
ORDER BY 前50%学生人数 DESC;
十、分页查询(LIMIT/OFFSET 或 ROW_NUMBER)
将大量查询结果按页分割,每次只返回指定页的数据(如:网页分页展示),不同数据库语法略有差异。
-- 分页查询语法(MySQL、PostgreSQL等)
SELECT 列名
FROM 表名
[WHERE 条件]
ORDER BY 排序列 -- 分页必须排序,否则结果不稳定
LIMIT 每页行数 OFFSET 起始位置; -- OFFSET:跳过的行数(第一页为0)
-- 分页查询语法(SQL Server,使用OFFSET FETCH)
SELECT 列名
FROM 表名
[WHERE 条件]
ORDER BY 排序列
OFFSET 起始位置 ROWS FETCH NEXT 每页行数 ROWS ONLY;
参数说明:
起始位置
:从第几条记录开始返回(第一页为0,第二页为“每页行数”,以此类推)。
示例:查询学生表中第3页的数据(每页10条,即返回第21-30条,按学号升序)。
-- MySQL/PostgreSQL写法
SELECT student_id, name, age
FROM students
ORDER BY student_id ASC
LIMIT 10 OFFSET 20; -- 跳过前20条,返回接下来的10条
-- SQL Server写法
SELECT student_id, name, age
FROM students
ORDER BY student_id ASC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
以上是最通用的10类SQL查询语句语法结构模板,能覆盖90%的SQL查询语句应用场景,不同数据库可能在细节上有差异(如:LIMIT vs TOP
、QUALIFY
、FULL JOIN
等),我们需结合具体数据库文档调整。在实际应用时,我们肯定会碰到一些复杂的应用场景。这个时候,我们可以将以上10类SQL查询语句语法结构模板按需叠加使用,如:连接解决多表关联,聚合解决分组统计,窗口函数解决行级计算,子查询解决逻辑拆分。如何叠加?可根据业务逻辑的复杂度,可以简单地两种组合,也可以多层嵌套。下面从实际常用的组合逻辑出发,介绍几类典型组合模式:
十一、基础组合(2种结构组合)
1、连接查询 + 聚合查询
场景:多表关联后分组统计,如:查询每个部门的员工人数,关联部门表获取部门名称。
-- 连接员工表和部门表,按部门分组统计人数
SELECT
d.dept_id AS 部门ID,
d.dept_name AS 部门名称,
COUNT(e.emp_id) AS 员工人数 -- 聚合函数:统计每个部门的员工数
FROM
departments AS d -- 部门表(左表)
LEFT JOIN
employees AS e -- 员工表(右表)
ON d.dept_id = e.dept_id -- 连接条件:部门ID关联
GROUP BY
d.dept_id, d.dept_name -- 按部门ID和名称分组(GROUP BY需包含非聚合列)
ORDER BY
员工人数 DESC; -- 按人数降序排列
2、窗口函数 + 子查询
场景:子查询筛选数据后,子查询结果作为窗口函数的数据源,用窗口函数计算,如:先通过子查询筛选近30天数据,再用窗口函数计算每日累计销量。
-- 子查询筛选近30天的订单,外层用窗口函数计算累计销售额
SELECT
order_date AS 订单日期,
daily_sales AS 当日销售额,
-- 窗口函数:按日期排序,计算从第一天到当前行的累计销售额
SUM(daily_sales) OVER (ORDER BY order_date) AS 累计销售额
FROM (
-- 子查询:按日期分组,计算每日销售额(筛选近30天数据)
SELECT
order_date,
SUM(amount) AS daily_sales -- 聚合每日销售额
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days' -- 筛选条件:近30天
GROUP BY order_date
) AS daily_data; -- 子查询结果作为临时表
3、连接查询 + 子查询
场景:子查询作为连接的数据源,多表关联后查询细节,如:查询每个订单对应的商品类别及该类别当月销量。
-- 连接订单明细表与商品表,同时关联子查询获取商品类别的当月销量
SELECT
od.order_id AS 订单ID,
p.product_name AS 商品名称,
p.category AS 商品类别,
od.quantity AS 订单数量,
monthly_category_sales.类别月销量 -- 子查询提供的类别当月总销量
FROM
order_details AS od -- 订单明细表
INNER JOIN
products AS p -- 商品表
ON od.product_id = p.product_id -- 连接条件:商品ID关联
INNER JOIN (
-- 子查询:按商品类别和月份分组,计算每个类别的当月总销量
SELECT
p2.category AS 类别,
DATE_FORMAT(od2.order_date, '%Y-%m') AS 月份, -- 格式化日期为“年-月”
SUM(od2.quantity) AS 类别月销量 -- 聚合:类别当月总销量
FROM order_details AS od2
INNER JOIN products AS p2 ON od2.product_id = p2.product_id
WHERE DATE_FORMAT(od2.order_date, '%Y-%m') = '2023-10' -- 限定2023年10月
GROUP BY p2.category, 月份
) AS monthly_category_sales -- 类别月销量临时表
-- 连接条件:商品类别一致,且订单日期属于子查询的月份
ON p.category = monthly_category_sales.类别
AND DATE_FORMAT(od.order_date, '%Y-%m') = monthly_category_sales.月份
WHERE DATE_FORMAT(od.order_date, '%Y-%m') = '2023-10'; -- 筛选10月订单
4、聚合查询 + 子查询
场景:分组聚合后,用子查询作为筛选条件,如:查询销售额高于全店平均销售额的商品类别。
-- 按商品类别分组统计销售额,筛选出高于全店平均销售额的类别
SELECT
p.category AS 商品类别,
SUM(od.quantity * p.price) AS 类别总销售额 -- 聚合:计算类别总销售额(数量×单价)
FROM
products AS p -- 商品表(含单价)
INNER JOIN
order_details AS od -- 订单明细表(含数量)
ON p.product_id = od.product_id -- 连接条件:商品ID关联
GROUP BY
p.category -- 按类别分组
HAVING
-- 筛选条件:类别总销售额 > 全店平均类别销售额(子查询计算)
SUM(od.quantity * p.price) > (
SELECT AVG(category_sales)
FROM (
-- 子查询2:先计算每个类别的总销售额(用于求平均)
SELECT SUM(od2.quantity * p2.price) AS category_sales
FROM products AS p2
INNER JOIN order_details AS od2 ON p2.product_id = od2.product_id
GROUP BY p2.category
) AS all_categories -- 所有类别的销售额临时表
)
ORDER BY 类别总销售额 DESC;
5、基础查询 + 窗口函数
场景:单表查询中直接使用窗口函数,不涉及多表或复杂聚合,如:查询学生成绩及班级内的排名。
-- 单表查询学生成绩,用窗口函数添加班级内排名
SELECT
student_id AS 学号,
name AS 姓名,
class_id AS 班级ID,
score AS 成绩,
-- 窗口函数1:按班级分组,成绩降序排名(相同成绩排名相同,下一名跳号)
RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS 班级排名,
-- 窗口函数2:按班级分组,计算班级内的成绩平均分(不合并行)
AVG(score) OVER (PARTITION BY class_id) AS 班级平均分
FROM
students -- 仅涉及学生表(单表)
WHERE
subject = '数学' -- 筛选数学科目成绩
ORDER BY
class_id, 班级排名; -- 按班级和排名排序
十二、多层嵌套组合(3种结构组合)
1、连接查询 + 聚合查询 + 子查询
场景:多表连接后分组,用子查询作为聚合筛选条件,如:查询销量高于同类产品平均销量的商品。
-- 连接产品表和订单明细表,分组统计销量,筛选高于同类平均的商品
SELECT
p.product_id AS 商品ID,
p.product_name AS 商品名称,
p.category AS 商品类别,
SUM(od.quantity) AS 总销量 -- 聚合函数:统计商品总销量
FROM
products AS p -- 商品表
INNER JOIN
order_details AS od -- 订单明细表
ON p.product_id = od.product_id -- 连接条件:商品ID关联
GROUP BY
p.product_id, p.product_name, p.category -- 按商品分组
HAVING
-- 筛选条件:总销量 > 该类别商品的平均销量(子查询计算)
SUM(od.quantity) > (
SELECT AVG(category_total)
FROM (
-- 子查询2:按类别分组,计算每个类别的商品销量(用于求平均)
SELECT SUM(quantity) AS category_total
FROM order_details
GROUP BY product_id
) AS sub
)
ORDER BY 总销量 DESC;
2、连接查询 + 窗口函数 + 子查询
场景:子查询生成临时数据,连接后用窗口函数排名,如:查询活跃用户的订单金额及用户消费排名。
-- 子查询筛选活跃用户,连接订单表,用窗口函数排名
SELECT
u.user_id AS 用户ID,
u.username AS 用户名,
o.order_amount AS 订单金额,
-- 窗口函数:按用户分组,订单金额降序排名(用户内的订单排名)
RANK() OVER (PARTITION BY u.user_id ORDER BY o.order_amount DESC) AS 用户订单排名
FROM
users AS u -- 用户表
INNER JOIN
orders AS o -- 订单表
ON u.user_id = o.user_id -- 连接条件:用户ID关联
INNER JOIN (
-- 子查询:筛选近90天有3次以上订单的活跃用户
SELECT user_id
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY user_id
HAVING COUNT(*) >= 3 -- 至少3次订单
) AS active_users -- 活跃用户临时表
ON u.user_id = active_users.user_id; -- 关联活跃用户
3、聚合查询 + 窗口函数 + 子查询
场景:先通过子查询筛选数据,再分组聚合统计,最后用窗口函数对聚合结果进行二次计算,如:按地区统计销售额,再对各地区销售额进行全国排名。
-- 子查询筛选有效订单,聚合后用窗口函数排名
SELECT
region AS 地区,
total_sales AS 地区总销售额,
-- 窗口函数:对所有地区的总销售额进行降序排名(不分组即全局排名)
RANK() OVER (ORDER BY total_sales DESC) AS 全国销售额排名,
-- 窗口函数:计算该地区销售额占全国总销售额的比例
ROUND(total_sales / SUM(total_sales) OVER () * 100, 2) AS 占全国比例(%)
FROM (
-- 子查询1:按地区分组,聚合计算各地区的总销售额(已筛选有效订单)
SELECT
r.region_name AS region, -- 地区名称
SUM(o.order_amount) AS total_sales -- 聚合函数:统计地区总销售额
FROM
orders AS o -- 订单表
INNER JOIN
users AS u -- 用户表(关联地区)
ON o.user_id = u.user_id
INNER JOIN
regions AS r -- 地区表
ON u.region_id = r.region_id
WHERE
o.order_status = 'completed' -- 筛选已完成的有效订单
AND o.order_date BETWEEN '2023-01-01' AND '2023-12-31' -- 限定年度
GROUP BY
r.region_name -- 按地区分组
) AS region_sales -- 子查询结果:地区-销售额临时表
ORDER BY
全国销售额排名; -- 按排名升序排列
结构说明:
(1)子查询:先筛选有效订单(已完成且在指定年度),关联用户表和地区表,按地区分组计算总销售额,生成临时表region_sales
;
(2)聚合查询:子查询内部通过SUM()
和GROUP BY
完成地区销售额的聚合统计;
(3)窗口函数:主查询中使用RANK()
对所有地区的销售额进行全局排名,使用SUM() OVER ()
计算全国总销售额并进一步求占比,实现对聚合结果的二次分析。
该组合适用于“先聚合统计、再全局对比”的场景,我们运用这个组合,既能得到分组数据,又能通过窗口函数在分组间进行横向比较。
十三、多层嵌套组合(3种以上结构)
场景:多层子查询嵌套,或叠加更多结构(如:多层子查询(嵌套子查询)+连接+聚合+窗口函数),如:按地区统计平均消费,再排名。
-- 多层嵌套:子查询筛选+连接+聚合+窗口函数排名
SELECT
region AS 地区,
avg_user_spend AS 地区平均消费,
-- 窗口函数:按地区平均消费降序排名
RANK() OVER (ORDER BY avg_user_spend DESC) AS 地区消费排名
FROM (
-- 子查询1:按地区分组,计算每个地区的用户平均消费
SELECT
r.region,
AVG(u.total_spend) AS avg_user_spend -- 聚合:地区平均消费
FROM
regions AS r -- 地区表
INNER JOIN
users AS u -- 用户表
ON r.region_id = u.region_id -- 连接条件:地区ID关联
INNER JOIN (
-- 子查询2:计算每个用户的总消费(近1年)
SELECT
user_id,
SUM(amount) AS total_spend -- 聚合:用户总消费
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '1 year' -- 筛选近1年订单
GROUP BY user_id
) AS user_spend -- 用户消费临时表
ON u.user_id = user_spend.user_id -- 关联用户消费数据
GROUP BY r.region -- 按地区分组
) AS region_spend; -- 地区消费临时表
在实际应用中,只要我们掌握了这些SQL查询语句模板,就能轻松应对基础查询任务,对于复杂的应用场景,我们只需灵活组合不同的SQL查询语句模板,结合具体数据库特性调整细节,也会轻松找到解决这些复杂任务的优化代码方案。
阅读原文:原文链接
该文章在 2025/9/1 11:05:23 编辑过