《SQL基础教程》第五章 SQL进阶之路:掌握高级查询的核心技巧
🔍 一、为什么需要高级查询?
实际业务中常需解决:
- 跨表关联分析(如订单关联用户信息)
- 动态分组统计(如部门平均工资排名)
- 复杂条件过滤(如筛选高于部门平均薪水的员工)
⚙️ 二、子查询:SQL的嵌套思维
本质:将一个查询结果作为另一个查询的条件或数据源
分类与典型场景:
类型 | 返回值 | 应用场景举例 | 示例片段(简写) |
---|---|---|---|
标量子查询 | 单值 | 比较薪资是否高于部门平均值 | SELECT * FROM emp WHERE salary > (SELECT AVG(salary) FROM emp) |
关联子查询 | 多行关联 | 按部门动态计算参照值 | SELECT name, salary FROM emp e1 WHERE salary > (SELECT AVG(salary) FROM emp e2 WHERE e1.dept=e2.dept) |
派生表查询 | 临时表 | 多步骤数据处理 | SELECT * FROM (SELECT dept, AVG(salary) avg_sal FROM emp GROUP BY dept) AS t WHERE avg_sal > 10000 |
避坑指南:
- 关联子查询中必须建立内外层关联(如
e1.dept=e2.dept
) - 避免在WHERE子句直接使用聚合函数(需用子查询替代)
🔗 三、关联查询:多表连接的魔法
核心语法:
SELECT 列
FROM 表A
[INNER|LEFT|RIGHT] JOIN 表B ON 连接条件
三大连接类型对比:
连接类型 | 保留数据范围 | 典型应用场景 |
---|---|---|
INNER JOIN | 两表交集数据 | 查询有订单的用户信息 |
LEFT JOIN | 左表全量+右表匹配 | 统计所有用户的订单量(含零订单) |
RIGHT JOIN | 右表全量+左表匹配 | 展示所有商品及其购买记录(含未售) 6 7 |
实战案例:
-- 查询所有员工及其经理名(含无经理员工)
SELECT e.name, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;
📐 四、函数与计算:数据加工利器
常用函数工具箱:
/* 字符串处理 */
CONCAT('姓', '名') → '姓名' -- 拼接字符串[1](@ref)
SUBSTRING('SQL教程', 1, 3) → 'SQL' -- 截取子串
/* 日期计算 */
DATEDIFF('2025-06-10', NOW()) -- 计算日期差
DATE_FORMAT(NOW(), '%Y年%m月') -- 格式化日期
/* 类型转换 */
CAST('123' AS SIGNED) -- 字符串转数字
COALESCE(NULL, 0) -- NULL替换为0[1,6](@ref)
🔄 五、进阶查询技巧
-
去重查询(DISTINCT)
SELECT DISTINCT dept FROM emp; -- 获取唯一部门列表
-
合并查询结果(UNION)
-- 合并不同表结构相似数据(自动去重) SELECT name FROM users UNION SELECT cust_name FROM orders;[6,7](@ref)
-
分组排序(窗口函数)
-- 按部门薪资排名(SQLite/MySQL 8.0+支持) SELECT name, salary, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank FROM emp;[6](@ref)
-
转置查询(行转列)
-- 将季度销售数据转为横向统计 SELECT product, SUM(CASE WHEN quarter='Q1' THEN sales END) AS Q1, SUM(CASE WHEN quarter='Q2' THEN sales END) AS Q2 FROM sales GROUP BY product;[6](@ref)
💎 六、性能与安全建议
- 索引优化:JOIN字段、WHERE条件列建索引提速
- 子查询陷阱:避免多层嵌套,改用JOIN或临时表
- 防笛卡积:JOIN必须写ON条件!