269条常用SQL查询语句:数据查询语言(DQL)的多场景应用示例

269条常用SQL查询语句:数据查询语言(DQL)的多场景应用示例在 SQL 语句中 SQL 查询语句站在 C 位 通过 SELECT 等子句从数据库表中检索所需数据 进行数据查询 分析和提取等数据操作

大家好,欢迎来到IT知识分享网。

在SQL语句中,SQL查询语句站在“C”位,通过SELECT等子句从数据库表中检索所需数据,进行数据查询、分析和提取等数据操作。在数据处理的各类场景中,我们都是通过SQL查询语句与数据库交互。所以,我们有必要对常用SQL查询语句做一个分类介绍,由于篇幅所限,一些高阶的常用SQL查询语句就没有选入。

一、基础查询

1、查询所有列

返回表中所有行的所有字段

SELECT * FROM employees; -- 从employees表查询所有列,*代表所有字段,适合快速查看表数据,生产环境尽量指定列名避免冗余 

2、查询指定列

返回表中所有行的指定字段

SELECT id, name, salary FROM employees; -- 查询employees表中所有行的id、name、salary列,仅返回需要的字段,提高效率 

3、列别名(AS)

为查询结果的列指定别名,增强可读性

SELECT id AS 员工编号, name AS 姓名, salary 工资 FROM employees; -- AS可省略,为列指定中文别名,适合报表展示 

4、移除重复行(DISTINCT单列)

去除指定列的重复值,返回唯一值

SELECT DISTINCT department_id FROM employees; -- 查询所有不重复的部门ID,仅保留department_id列的唯一值 

5、移除多列重复行(DISTINCT多列)

当多列组合重复时去重,仅保留唯一组合

SELECT DISTINCT department_id, job_id FROM employees; -- 去除department_id和job_id组合重复的行,两列同时相同才视为重复 

6、常量列查询

在结果中添加固定值列,用来标识来源或分类

SELECT id, name, '正式员工' AS 员工类型 FROM employees; -- 新增"员工类型"列,所有行均为固定值"正式员工" 

7、计算列(算术运算)

对数值列进行算术计算并返回结果

SELECT id, name, salary, salary * 12 AS 年薪 FROM employees; -- 计算年薪(月薪*12),作为新列返回 

8、字符串拼接(CONCAT)

将多个字符串字段拼接为一个字段

SELECT CONCAT(first_name, ' ', last_name) AS 全名 FROM employees; -- 拼接名和姓,中间加空格,适合生成完整名称 

9、条件拼接(CONCAT_WS)

使用指定分隔符拼接字符串,自动忽略NULL

SELECT CONCAT_WS('-', year, month, day) AS 日期 FROM orders; -- 用"-"拼接年、月、日,若某字段为NULL则跳过,避免结果为NULL 

10、字符串长度(LENGTH)

返回字符串的字节长度

SELECT name, LENGTH(name) AS 名称长度 FROM products; -- 计算商品名称的字节长度,适合校验名称长度是否符合规范 

11、字符长度(CHAR_LENGTH)

返回字符串的字符数量(与编码无关)

SELECT name, CHAR_LENGTH(name) AS 字符数 FROM users; -- 计算用户名的字符个数,如:"张三"返回2,适合限制字符数场景 

12、字符串截取(SUBSTRING)

从指定位置截取字符串的部分内容

SELECT SUBSTRING(phone, 1, 3) AS 区号 FROM customers; -- 从phone列第1位开始,截取3个字符(如:手机号前3位区号) 

13、字符串替换(REPLACE)

替换字符串中的指定子串

SELECT REPLACE(email, 'old.com', 'new.com') AS 新邮箱 FROM users; -- 将邮箱中的"old.com"替换为"new.com" 

14、大小写转换(UPPER/LOWER)

将字符串转换为全大写或全小写

SELECT UPPER(name) AS 大写名称, LOWER(email) AS 小写邮箱 FROM users; -- 名称转大写,邮箱转小写统一格式 

15、空值处理(IFNULL/COALESCE)

将NULL值替换为指定默认值

SELECT name, IFNULL(commission_pct, 0) AS 佣金比例 FROM employees; -- MySQL用IFNULL,将NULL佣金比例替换为0 SELECT name, COALESCE(commission_pct, 0) AS 佣金比例 FROM employees; -- 通用函数COALESCE,效果同上,支持多参数 

二、条件查询(WHERE)

16、等于条件(=)

筛选字段值等于指定值的行

SELECT * FROM employees WHERE department_id = 30; -- 查询部门ID为30的所有员工 

17、不等于条件(!= 或 <>)

筛选字段值不等于指定值的行

SELECT * FROM employees WHERE department_id != 30; -- 查询部门ID不是30的员工,!=和<>功能相同 

18、大于条件(>)

筛选字段值大于指定值的行

SELECT * FROM employees WHERE salary > 5000; -- 查询薪资大于5000的员工 

19、小于条件(<)

筛选字段值小于指定值的行

SELECT * FROM products WHERE price < 100; -- 查询价格小于100的商品 

20、大于等于条件(>=)

筛选字段值大于或等于指定值的行

SELECT * FROM orders WHERE quantity >= 10; -- 查询订单数量大于等于10的订单 

21、小于等于条件(<=)

筛选字段值小于或等于指定值的行

SELECT * FROM users WHERE age <= 18; -- 查询年龄小于等于18的用户(未成年人) 

22、范围查询(BETWEEN…AND…)

筛选字段值在指定范围内(包含边界)的行

SELECT * FROM employees WHERE salary BETWEEN 5000 AND 10000; -- 查询薪资在5000到10000之间的员工(包含5000和10000) 

23、不在范围内(NOT BETWEEN…AND…)

筛选字段值不在指定范围内的行

SELECT * FROM products WHERE price NOT BETWEEN 100 AND 500; -- 查询价格不在100到500之间的商品 

24、枚举值查询(IN)

筛选字段值等于枚举列表中任意值的行

SELECT * FROM employees WHERE department_id IN (10, 20, 30); -- 查询部门ID为10、20或30的员工,等价于多个OR条件 

25、不在枚举值中(NOT IN)

筛选字段值不等于枚举列表中所有值的行

SELECT * FROM users WHERE country NOT IN ('USA', 'CN'); -- 查询国家不是美国或中国的用户 

26、空值查询(IS NULL)

筛选字段值为NULL的行(NULL不能用=判断)

SELECT * FROM employees WHERE manager_id IS NULL; -- 查询没有经理的员工(manager_id为NULL) 

27、非空值查询(IS NOT NULL)

筛选字段值不为NULL的行

SELECT * FROM customers WHERE email IS NOT NULL; -- 查询有邮箱的客户(email不为NULL) 

28、模糊查询(LIKE %)

按字符串模式匹配,%代表任意长度字符(包括0个)

SELECT * FROM products WHERE name LIKE '苹果%'; -- 查询名称以"苹果"开头的商品(如:"苹果手机"、"苹果电脑") SELECT * FROM products WHERE name LIKE '%手机'; -- 查询名称以"手机"结尾的商品 SELECT * FROM products WHERE name LIKE '%智能%'; -- 查询名称包含"智能"的商品 

29、模糊查询(LIKE _)

按字符串模式匹配,_代表单个任意字符

SELECT * FROM users WHERE username LIKE '张_'; -- 查询用户名是"张"开头且长度为2的用户(如:"张三"、"张四") SELECT * FROM users WHERE phone LIKE '138____5678'; -- 查询138开头、以5678结尾,中间4位任意的手机号 

30、不匹配模糊查询(NOT LIKE)

筛选不匹配指定模式的行

SELECT * FROM articles WHERE title NOT LIKE '%广告%'; -- 查询标题不包含"广告"的文章 

31、逻辑与(AND)

同时满足多个条件的行

SELECT * FROM employees WHERE department_id = 30 AND salary > 6000; -- 查询30部门中薪资大于6000的员工 

32、逻辑或(OR)

满足任意一个条件的行

SELECT * FROM employees WHERE department_id = 30 OR salary > 10000; -- 查询30部门员工或薪资大于10000的员工 

33、逻辑非(NOT)

取反条件的结果

SELECT * FROM employees WHERE NOT (salary > 5000); -- 查询薪资不大于5000的员工(等价于salary <= 5000) 

34、条件优先级(括号)

改变条件的执行顺序,括号内条件优先执行

SELECT * FROM employees WHERE (department_id = 30 OR department_id = 40) AND salary > 6000; -- 先筛选30或40部门,再筛选其中薪资>6000的员工 

35、正则匹配(REGEXP)

按正则表达式模式匹配字符串

SELECT * FROM users WHERE phone REGEXP '^1[3-9][0-9]{9}#39;; -- 查询符合手机号规则的用户(1开头,第2位3-9,共11位) SELECT * FROM articles WHERE content REGEXP 'Java|Python'; -- 查询内容包含Java或Python的文章 

36、不匹配正则(NOT REGEXP)

筛选不匹配正则表达式的行

SELECT * FROM comments WHERE content NOT REGEXP '[0-9]{6,}'; -- 查询内容不包含6位以上数字的评论(避免包含手机号等) 

37、日期等于(DATE)

筛选日期字段等于指定日期的行

SELECT * FROM orders WHERE DATE(order_date) = '2023-10-01'; -- 查询2023年10月1日的订单(忽略时间部分) 

38、日期范围(DATE BETWEEN)

筛选日期在指定范围内的行

SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'; -- 查询2023年全年的订单 

39、年份查询(YEAR)

筛选指定年份的行

SELECT * FROM employees WHERE YEAR(hire_date) = 2020; -- 查询2020年入职的员工 

40、月份查询(MONTH)

筛选指定月份的行

SELECT * FROM orders WHERE MONTH(order_date) = 12; -- 查询12月份的订单(所有年份) 

41、季度查询(QUARTER)

筛选指定季度的行(1-4季度)

SELECT * FROM sales WHERE QUARTER(sale_date) = 4; -- 查询第4季度(10-12月)的销售记录 

42、日期差(DATEDIFF)

按两个日期的差值筛选行

SELECT * FROM orders WHERE DATEDIFF(ship_date, order_date) > 3; -- 查询发货时间比下单时间晚3天以上的订单 

三、排序查询(ORDER BY)

43、单列升序(ASC)

按指定列从小到大排序(默认升序)

SELECT * FROM employees ORDER BY salary ASC; -- 按薪资升序排列,ASC可省略,从低到高显示 

44、单列降序(DESC)

按指定列从大到小排序

SELECT * FROM employees ORDER BY salary DESC; -- 按薪资降序排列,从高到低显示 

45、多列排序(先升后降)

先按第一列排序,第一列相同则按第二列排序

SELECT * FROM employees ORDER BY department_id ASC, salary DESC; -- 先按部门ID升序,同部门内按薪资降序 

46、按别名排序

按查询结果中的别名列排序

SELECT id, name, salary * 12 AS 年薪 FROM employees ORDER BY 年薪 DESC; -- 按计算后的"年薪"降序排列 

47、按列位置排序(不推荐)

按查询列的位置(从1开始)排序

SELECT name, salary FROM employees ORDER BY 2 DESC; -- 按第2列(salary)降序,不推荐,列顺序变化会出错 

48、按字符串长度排序

按字符串字段的长度排序

SELECT name FROM products ORDER BY CHAR_LENGTH(name) ASC; -- 按商品名称的字符长度升序(短名称在前) 

49、按日期排序

按日期字段的时间先后排序

SELECT * FROM orders ORDER BY order_date DESC; -- 按下单日期降序(最新订单在前) 

50、按NULL排序(NULLS FIRST)

将NULL值排在最前面

SELECT * FROM employees ORDER BY manager_id NULLS FIRST; -- PostgreSQL语法,manager_id为NULL的行排在前面 

51、按NULL排序(NULLS LAST)

将NULL值排在最后面

SELECT * FROM employees ORDER BY manager_id NULLS LAST; -- PostgreSQL语法,manager_id为NULL的行排在后面 

52、按大小写排序(区分大小写)

区分字符串大小写进行排序(依赖数据库 collation)

SELECT name FROM users ORDER BY name COLLATE 'utf8_bin'; -- MySQL中按二进制排序,区分大小写(A在a前) 

53、按中文拼音排序

按中文的拼音首字母排序

SELECT name FROM users ORDER BY name COLLATE 'zh_CN.utf8'; -- 按中文拼音排序(如:"张三"在"李四"前) 

54、按计算结果排序

按字段计算后的结果排序

SELECT name, salary, commission_pct FROM employees ORDER BY salary * (1 + IFNULL(commission_pct, 0)) DESC; -- 按薪资加佣金的总和降序 

55、按枚举值排序

按枚举字段的预设顺序排序

SELECT * FROM orders ORDER BY FIELD(status, 'pending', 'processing', 'shipped', 'delivered'); -- MySQL用FIELD指定枚举顺序,按pending→processing→shipped→delivered排序 

56、按条件排序(CASE)

根据条件动态指定排序规则

SELECT * FROM employees ORDER BY CASE WHEN department_id = 30 THEN salary ELSE 0 END DESC; -- 30部门员工按薪资降序,其他部门排在后面(按0排序) 

57、随机排序(RAND)

随机返回表中的行(适合随机抽样)

SELECT * FROM products ORDER BY RAND() LIMIT 5; -- MySQL用RAND()随机排序,取前5条(随机推荐5个商品) 

四、聚合查询(GROUP BY & 聚合函数)

58、计数(COUNT(*))

统计行数(包括NULL值)

SELECT COUNT(*) AS 总员工数 FROM employees; -- 统计employees表的总行数,包含所有字段为NULL的行 

59、非空计数(COUNT(列名))

统计指定列非NULL值的行数

SELECT COUNT(email) AS 有邮箱的用户数 FROM users; -- 统计email列不为NULL的行数(即有邮箱的用户数量) 

60、去重计数(COUNT(DISTINCT 列名))

统计指定列非重复且非NULL值的数量

SELECT COUNT(DISTINCT department_id) AS 部门数量 FROM employees; -- 统计不重复的部门ID数量(即公司有多少个部门) 

61、求和(SUM)

计算指定数值列的总和

SELECT SUM(sales_amount) AS 总销售额 FROM sales; -- 计算所有销售记录的金额总和 

62、平均值(AVG)

计算指定数值列的平均值(忽略NULL)

SELECT AVG(salary) AS 平均薪资 FROM employees; -- 计算员工的平均薪资,自动排除salary为NULL的行 

63、最大值(MAX)

查询指定列的最大值

SELECT MAX(price) AS 最高价格 FROM products; -- 查询商品中的最高价格 

64、最小值(MIN)

查询指定列的最小值

SELECT MIN(hire_date) AS 最早入职日期 FROM employees; -- 查询最早的员工入职日期 

65、单字段分组(GROUP BY)

按指定列分组,对每组进行聚合计算

SELECT department_id AS 部门ID, COUNT(*) AS 部门人数 FROM employees GROUP BY department_id; -- 按部门ID分组,统计每个部门的员工数量 

66、多字段分组(GROUP BY多列)

按多个列的组合分组,更细致地划分组

SELECT department_id, job_id, AVG(salary) AS 平均薪资 FROM employees GROUP BY department_id, job_id; -- 按部门和岗位分组,计算每个部门内各岗位的平均薪资 

67、分组筛选(HAVING)

对GROUP BY后的组结果进行筛选(类似WHERE但用于组)

SELECT department_id, COUNT(*) AS 人数 FROM employees GROUP BY department_id HAVING COUNT(*) > 10; -- 筛选出员工数大于10的部门 

68、分组+排序

对分组后的结果按指定规则排序

SELECT department_id, SUM(salary) AS 部门总薪资 FROM employees GROUP BY department_id ORDER BY 部门总薪资 DESC; -- 按部门分组计算总薪资,并按总薪资降序排列 

69、分组前筛选(WHERE + GROUP BY)

先筛选行,再对符合条件的行分组

SELECT department_id, AVG(salary) AS 平均薪资 FROM employees WHERE hire_date >= '2020-01-01' GROUP BY department_id; -- 先筛选2020年及以后入职的员工,再按部门计算平均薪资 

70、分组前后都筛选(WHERE + GROUP BY + HAVING)

先筛行,再分组,最后筛组

SELECT department_id, AVG(salary) AS 平均薪资 FROM employees WHERE salary > 3000 GROUP BY department_id HAVING AVG(salary) > 6000; -- 先筛薪资>3000的员工,分组后筛选平均薪资>6000的部门 

71、总和占比(SUM + 子查询)

计算每组总和占总体的比例

SELECT department_id, SUM(salary) AS 部门总薪资, SUM(salary)/(SELECT SUM(salary) FROM employees) AS 占比 FROM employees GROUP BY department_id; -- 计算各部门薪资占公司总薪资的比例 

72、分组后拼接字符串(GROUP_CONCAT)

将分组内的字符串字段拼接为一个字符串(MySQL特有)

SELECT department_id, GROUP_CONCAT(name SEPARATOR ',') AS 员工姓名 FROM employees GROUP BY department_id; -- 按部门分组,将每个部门的员工姓名用逗号拼接 

73、分组统计非空值(COUNT + GROUP BY)

按组统计指定列的非空值数量

SELECT department_id, COUNT(phone) AS 有电话的员工数 FROM employees GROUP BY department_id; -- 按部门统计有电话号码的员工数量 

74、分组计算差异(MAX – MIN)

计算每组内指定列的最大值与最小值之差

SELECT department_id, MAX(salary) - MIN(salary) AS 薪资差距 FROM employees GROUP BY department_id; -- 计算每个部门内的最大薪资与最小薪资的差值 

75、分组条件计数(SUM + CASE)

按组统计满足特定条件的行数

SELECT department_id, SUM(CASE WHEN salary > 8000 THEN 1 ELSE 0 END) AS 高薪员工数 FROM employees GROUP BY department_id; -- 按部门统计薪资>8000的员工数量 

76、按年份分组

按日期字段的年份分组统计

SELECT YEAR(order_date) AS 年份, COUNT(*) AS 订单数 FROM orders GROUP BY YEAR(order_date); -- 按年份统计每年的订单数量 

77、按季度分组

按日期字段的季度分组统计

SELECT YEAR(order_date) AS 年份, QUARTER(order_date) AS 季度, SUM(amount) AS 季度销售额 FROM orders GROUP BY 年份, 季度; -- 按年份和季度统计销售额 

78、按月份分组

按日期字段的月份分组统计

SELECT MONTH(create_time) AS 月份, COUNT(*) AS 注册人数 FROM users GROUP BY 月份; -- 按月份统计每月的用户注册量(不区分年份) 

79、分组后取前N组

对分组结果排序后取前N个组

SELECT department_id, SUM(sales) AS 总销售额 FROM sales GROUP BY department_id ORDER BY 总销售额 DESC LIMIT 3; -- 按部门分组计算总销售额,取前三名的部门 

80、排除特定组(HAVING NOT)

在分组后排除符合特定条件的组

SELECT department_id, AVG(salary) AS 平均薪资 FROM employees GROUP BY department_id HAVING NOT AVG(salary) < 5000; -- 排除平均薪资<5000的部门(即保留≥5000的部门) 

81、分组统计NULL值(COUNT + IS NULL)

按组统计指定列中NULL值的数量

SELECT department_id, SUM(CASE WHEN manager_id IS NULL THEN 1 ELSE 0 END) AS 无经理人数 FROM employees GROUP BY department_id; -- 按部门统计没有经理的员工数量 

82、多聚合函数组合

在一次分组中计算多个聚合结果

SELECT department_id, COUNT(*) AS 人数, AVG(salary) AS 平均薪资, MAX(salary) AS 最高薪资, MIN(salary) AS 最低薪资 FROM employees GROUP BY department_id; -- 按部门同时计算人数、平均/最高/最低薪资 

83、按表达式分组

按字段计算后的结果分组

SELECT salary DIV 1000 AS 薪资等级(千), COUNT(*) AS 人数 FROM employees GROUP BY 薪资等级(千); -- 按薪资除以1000的整数部分分组(如:3000-3999为3级) 

84、按别名分组

按查询中的别名进行分组(部分数据库支持)

SELECT department_id AS dept_id, COUNT(*) AS 人数 FROM employees GROUP BY dept_id; -- 按别名dept_id分组(等价于按department_id分组,增强可读性) 

85、空组处理(COALESCE)

将NULL分组值替换为指定名称

SELECT COALESCE(department_id, '无部门') AS 部门ID, COUNT(*) AS 人数 FROM employees GROUP BY department_id; -- 把department_id为NULL的组显示为"无部门" 

86、分组统计比例(百分比)

计算每组数量占总体的百分比

SELECT gender, COUNT(*) AS 人数, COUNT(*)/(SELECT COUNT(*) FROM users) * 100 AS 占比(%) FROM users GROUP BY gender; -- 按性别统计人数及占比(保留两位小数可加ROUND函数) 

五、多表连接查询(JOIN)

87、内连接(INNER JOIN)

返回两表中满足连接条件的交集数据

SELECT e.name, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.id; -- 关联员工表(e)和部门表(d),只返回有对应部门的员工及其部门名称 

88、内连接简化写法(逗号+WHERE)

用逗号分隔表,WHERE指定连接条件(等价于INNER JOIN)

SELECT e.name, d.department_name FROM employees e, departments d WHERE e.department_id = d.id; -- 老式写法,功能同INNER JOIN,推荐用显式JOIN更清晰 

89、左连接(LEFT JOIN)

返回左表所有行,右表匹配不到则用NULL填充

SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id; -- 返回所有员工,有部门则显示部门名,无部门则部门名为NULL 

90、左连接筛选右表NULL

用左连接查询左表中无右表匹配的数据

SELECT e.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id WHERE d.id IS NULL; -- 查询没有对应部门的员工(右表无匹配) 

91、右连接(RIGHT JOIN)

返回右表所有行,左表匹配不到则用NULL填充

SELECT d.department_name, e.name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id; -- 返回所有部门,有员工则显示员工名,无员工则员工名为NULL 

92、右连接筛选左表NULL

用右连接查询右表中无左表匹配的数据

SELECT d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id WHERE e.id IS NULL; -- 查询没有员工的部门(左表无匹配) 

93、全外连接(FULL JOIN)

返回左右表所有行,无匹配则用NULL填充(MySQL不直接支持)

-- PostgreSQL/Oracle支持 SELECT e.name, d.department_name FROM employees e FULL JOIN departments d ON e.department_id = d.id; -- 返回所有员工和所有部门,无匹配则对应字段为NULL 

94、MySQL模拟全外连接(UNION)

在MySQL中用LEFT JOIN + RIGHT JOIN + UNION模拟全外连接

SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id UNION SELECT e.name, d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id; -- 合并左连接和右连接结果,去重后等价于全外连接 

95、三表连接(INNER JOIN)

关联三个表,返回满足所有连接条件的数据

SELECT e.name, d.department_name, l.city FROM employees e INNER JOIN departments d ON e.department_id = d.id INNER JOIN locations l ON d.location_id = l.id; -- 关联员工表→部门表→地点表,查询员工姓名、部门名、部门所在城市 

96、混合连接(LEFT JOIN + INNER JOIN)

结合不同连接类型关联多表

SELECT e.name, d.department_name, l.city FROM employees e LEFT JOIN departments d ON e.department_id = d.id INNER JOIN locations l ON d.location_id = l.id; -- 员工左连接部门(保留所有员工),部门内连接地点(仅保留有地点的部门) 

97、交叉连接(CROSS JOIN)

返回两表的笛卡尔积(所有可能的行组合)

SELECT p.product_name, c.category_name FROM products p CROSS JOIN categories c; -- 返回所有商品与所有类别的组合(行数=商品数×类别数,慎用,数据量大时效率低) 

98、带条件的交叉连接

对交叉连接的结果进行筛选(等价于内连接)

SELECT p.product_name, c.category_name FROM products p CROSS JOIN categories c WHERE p.category_id = c.id; -- 等价于INNER JOIN,通过WHERE筛选出匹配的商品和类别 

99、自连接(同表连接)

将表与自身连接,查询表内关联数据(如:层级关系)

SELECT e.name AS 员工, m.name AS 经理 FROM employees e LEFT JOIN employees m ON e.manager_id = m.id; -- 员工表自连接,查询每个员工及其对应的经理(无经理则为NULL) 

100、自连接查询层级数据

通过自连接查询多层级关系(如:部门上下级)

SELECT d1.department_name AS 父部门, d2.department_name AS 子部门 FROM departments d1 LEFT JOIN departments d2 ON d2.parent_id = d1.id; -- 部门表自连接,查询父部门和对应的子部门 

101、连接+筛选(ON后条件)

在连接时就筛选右表数据(区别于WHERE)

SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id AND d.location_id = 1; -- 左连接时仅关联location_id=1的部门,保留所有员工,部门名仅显示符合条件的 

102、连接+分组

连接多表后按指定字段分组统计

SELECT d.department_name, COUNT(e.id) AS 员工数 FROM departments d LEFT JOIN employees e ON d.id = e.department_id GROUP BY d.department_name; -- 按部门名分组,统计每个部门的员工数量(包括无员工的部门) 

103、连接+排序

对连接后的结果按指定字段排序

SELECT o.order_id, c.customer_name, o.order_date FROM orders o INNER JOIN customers c ON o.customer_id = c.id ORDER BY o.order_date DESC, o.order_id ASC; -- 按订单日期降序、订单ID升序排列关联结果 

104、多条件连接(AND)

通过多个条件关联两表

SELECT e.name, p.project_name FROM employees e INNER JOIN employee_projects ep ON e.id = ep.employee_id INNER JOIN projects p ON ep.project_id = p.id AND p.status = 'active'; -- 关联员工与项目,仅包含状态为"active"的项目 

105、连接+计算列

对连接后的结果进行字段计算

SELECT o.order_id, c.customer_name, (o.amount - o.discount) AS 实际支付金额 FROM orders o INNER JOIN customers c ON o.customer_id = c.id; -- 计算订单实际支付金额(金额-折扣)并关联客户信息 

106、左连接排除匹配项

查询左表中与右表无匹配的数据(反连接)

SELECT c.customer_id, c.customer_name FROM customers c LEFT JOIN orders o ON c.id = o.customer_id WHERE o.order_id IS NULL; -- 查询没有下过订单的客户(左表有,右表无匹配) 

107、右连接排除匹配项

查询右表中与左表无匹配的数据

SELECT p.product_id, p.product_name FROM orders o RIGHT JOIN products p ON o.product_id = p.id WHERE o.order_id IS NULL; -- 查询从未被订购过的商品(右表有,左表无匹配) 

108、连接使用别名简化

为表指定别名,简化多表连接的语法

SELECT u.username, o.order_id, p.product_name FROM users u INNER JOIN orders o ON u.id = o.user_id INNER JOIN order_products op ON o.id = op.order_id INNER JOIN products p ON op.product_id = p.id; -- 多表连接时用短别名(u、o、op、p)简化代码 

109、自然连接(NATURAL JOIN)

自动按同名字段连接(不推荐,依赖字段名,易出错)

SELECT e.name, d.department_name FROM employees e NATURAL JOIN departments d; -- 自动按两表中同名的字段(如:id)连接,不建议使用,字段名变化会导致错误 

110、USING子句连接

指定连接的字段名(比NATURAL JOIN更明确)

SELECT e.name, d.department_name FROM employees e INNER JOIN departments d USING (department_id); -- 明确指定按department_id字段连接,比ON更简洁(要求两表字段名相同) 

111、四表连接查询

关联四个表获取多层级数据

SELECT o.order_id, c.name, p.product_name, s.supplier_name FROM orders o INNER JOIN customers c ON o.customer_id = c.id INNER JOIN order_items oi ON o.id = oi.order_id INNER JOIN products p ON oi.product_id = p.id INNER JOIN suppliers s ON p.supplier_id = s.id; -- 关联订单→客户→订单项→商品→供应商,获取完整订单链信息 

112、左连接保留所有左表数据

确保左表所有行都被返回,无论右表是否有匹配

SELECT d.department_name, AVG(e.salary) AS 平均薪资 FROM departments d LEFT JOIN employees e ON d.id = e.department_id GROUP BY d.department_name; -- 计算所有部门的平均薪资,无员工的部门平均薪资为NULL 

113、连接后去重(DISTINCT)

去除连接后产生的重复行

SELECT DISTINCT c.customer_name, p.product_name FROM customers c INNER JOIN orders o ON c.id = o.customer_id INNER JOIN order_items oi ON o.id = oi.order_id INNER JOIN products p ON oi.product_id = p.id; -- 去重后返回客户购买过的商品(每个客户-商品组合只出现一次) 

114、条件连接(不同条件关联)

根据不同条件关联不同的表

SELECT t.transaction_id, t.amount, u.username AS 用户, m.merchant_name AS 商户 FROM transactions t LEFT JOIN users u ON t.type = 'user' AND t.related_id = u.id LEFT JOIN merchants m ON t.type = 'merchant' AND t.related_id = m.id; -- 按交易类型关联用户表或商户表 

115、连接查询聚合后过滤

连接多表后分组,再筛选组结果

SELECT c.country, COUNT(o.order_id) AS 订单数 FROM customers c INNER JOIN orders o ON c.id = o.customer_id GROUP BY c.country HAVING COUNT(o.order_id) > 100; -- 按国家统计订单数,筛选订单数>100的国家 

116、连接时使用函数

在连接条件中使用函数处理字段

SELECT e.name, d.department_name FROM employees e INNER JOIN departments d ON UPPER(e.department_code) = d.code; -- 忽略大小写匹配部门编码(e的编码转大写后与d的code连接) 

六、子查询(Subquery)

117、标量子查询(SELECT子句中)

返回单个值,作为主查询的列使用

SELECT name, salary, (SELECT AVG(salary) FROM employees) AS 公司平均薪资 FROM employees; -- 子查询返回公司平均薪资,作为每个员工记录的对比列 

118、标量子查询(WHERE子句中)

返回单个值,用在WHERE条件判断

SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees); -- 子查询计算平均薪资,主查询返回薪资高于平均值的员工 

119、列子查询(IN)

返回一列多行,主查询用IN判断是否在结果中

SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE country = 'China'); -- 子查询返回中国客户ID,主查询返回这些客户的订单 

120、列子查询(NOT IN)

返回一列多行,主查询用NOT IN判断是否不在结果中

SELECT * FROM products WHERE category_id NOT IN (SELECT id FROM categories WHERE status = 'disabled'); -- 子查询返回禁用的分类ID,主查询返回不在其中的商品 

121、列子查询(ANY)

主查询条件满足子查询结果中的任意一个

SELECT name, salary FROM employees WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 30); -- 子查询返回30部门的所有薪资,主查询返回薪资高于其中任意一个的员工 

122、列子查询(ALL)

主查询条件满足子查询结果中的所有值

SELECT name, salary FROM employees WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 30); -- 子查询返回30部门的所有薪资,主查询返回薪资高于其中所有值的员工(即高于30部门最高薪资) 

123、行子查询(=)

返回一行多列,主查询用多列匹配

SELECT * FROM employees WHERE (department_id, salary) = (SELECT department_id, MAX(salary) FROM employees GROUP BY department_id HAVING department_id = 30); -- 子查询返回30部门的最高薪资行,主查询匹配该部门且薪资等于最高值的员工 

124、行子查询(IN)

返回多行多列,主查询用多列判断是否在结果中

SELECT * FROM employees WHERE (department_id, job_id) IN (SELECT department_id, job_id FROM employees WHERE salary > 10000); -- 子查询返回薪资>10000的部门+岗位组合,主查询返回这些组合中的所有员工 

125、表子查询(FROM子句中)

返回一个结果集,作为主查询的数据源(派生表)

SELECT dept_id, avg_salary FROM (SELECT department_id AS dept_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id) AS dept_avg WHERE avg_salary > 6000; -- 子查询作为派生表(dept_avg),主查询筛选平均薪资>6000的部门 

126、表子查询+连接

将表子查询与其他表连接

SELECT e.name, dept_avg.avg_salary FROM employees e INNER JOIN (SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id) AS dept_avg ON e.department_id = dept_avg.department_id; -- 子查询生成部门平均薪资表,与员工表连接,显示每个员工及其部门平均薪资 

127、 EXISTS子查询(存在)

判断子查询是否有结果,有则返回TRUE

SELECT * FROM customers c WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id AND o.amount > 1000); -- 子查询判断客户是否有金额>1000的订单,主查询返回满足条件的客户 

128、NOT EXISTS子查询(不存在)

判断子查询是否无结果,无则返回TRUE

SELECT * FROM products p WHERE NOT EXISTS (SELECT 1 FROM order_items oi WHERE oi.product_id = p.id); -- 子查询判断商品是否被订购过,主查询返回从未被订购的商品(等价于左连接筛选NULL) 

129、子查询在HAVING中

在分组筛选条件中使用子查询

SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id HAVING AVG(salary) > (SELECT AVG(salary) FROM employees); -- 子查询返回公司平均薪资,主查询筛选部门平均薪资高于公司平均值的部门 

130、多层子查询(嵌套)

子查询中包含另一个子查询(最多支持多层)

SELECT name FROM employees WHERE department_id = (SELECT id FROM departments WHERE location_id = (SELECT id FROM locations WHERE city = 'Beijing')); -- 内层子查询返回北京的location_id,中层返回该地点的部门ID,外层返回该部门的员工 

131、子查询与JOIN等价转换

将子查询改写为JOIN(有时性能更优)

-- 子查询版本 SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE name = 'Sales'); -- 等价JOIN版本 SELECT e.name FROM employees e INNER JOIN departments d ON e.department_id = d.id WHERE d.name = 'Sales'; -- 功能相同,JOIN在某些场景下效率更高 

132、子查询限制结果(LIMIT)

子查询中用LIMIT限制返回行数

SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers ORDER BY register_date DESC LIMIT 10); -- 子查询返回最新注册的10个客户ID,主查询返回这些客户的订单 

133、子查询使用聚合函数

子查询中包含聚合计算

SELECT * FROM products WHERE price > (SELECT MAX(price) FROM products WHERE category_id = 5); -- 子查询返回5类商品的最高价格,主查询返回价格高于该值的商品 

134、相关子查询(依赖主查询)

子查询引用主查询的字段,每行执行一次子查询

SELECT e1.name, e1.salary FROM employees e1 WHERE e1.salary > (SELECT AVG(e2.salary) FROM employees e2 WHERE e2.department_id = e1.department_id); -- 子查询依赖主查询的department_id,计算同部门平均薪资,主查询返回高于本部门平均的员工 

135、相关子查询(EXISTS)

相关子查询与EXISTS结合,每行判断一次

SELECT d.department_name FROM departments d WHERE EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.id AND e.salary > 10000); -- 子查询依赖主查询的部门ID,判断部门是否有薪资>10000的员工,主查询返回满足条件的部门 

136、子查询作为计算字段

子查询结果作为主查询的计算列

SELECT o.order_id, o.amount, (SELECT COUNT(*) FROM order_items oi WHERE oi.order_id = o.id) AS 商品数量 FROM orders o; -- 子查询依赖主查询的订单ID,计算每个订单包含的商品数量,作为订单记录的列 

137、子查询筛选最大/最小值对应行

查询某列最大/最小值所在的完整行

SELECT * FROM employees WHERE salary = (SELECT MAX(salary) FROM employees); -- 子查询返回最高薪资,主查询返回该薪资对应的员工(可能多个) 

138、子查询与日期函数

子查询中使用日期函数筛选数据

SELECT * FROM orders WHERE order_date > (SELECT MAX(order_date) FROM orders WHERE customer_id = 100); -- 子查询返回客户100的最后下单日期,主查询返回所有晚于该日期的订单 

139、子查询返回多个字段

子查询返回多列,主查询引用多个字段

SELECT e.name, (SELECT CONCAT(d.name, '-', l.city) FROM departments d INNER JOIN locations l ON d.location_id = l.id WHERE d.id = e.department_id) AS 部门及城市 FROM employees e; -- 子查询返回部门名+城市的拼接值,作为员工记录的列 

140、子查询在ORDER BY中

在排序条件中使用子查询结果

SELECT name, department_id FROM employees ORDER BY (SELECT location_id FROM departments WHERE id = employees.department_id) ASC; -- 按部门所在地点ID排序,子查询返回每个员工所属部门的location_id 

141、子查询排除特定数据

用子查询排除不需要的数据

SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM banned_users); -- 子查询返回被禁用户ID,主查询返回未被禁的用户 

142、子查询与DISTINCT

子查询中去重后供主查询使用

SELECT * FROM products WHERE category_id IN (SELECT DISTINCT category_id FROM products WHERE price < 100); -- 子查询返回有低价商品的分类ID(去重),主查询返回这些分类的所有商品 

143、子查询与CASE

在子查询中使用条件逻辑

SELECT name, (SELECT CASE WHEN AVG(salary) > 8000 THEN '高' ELSE '中' END FROM employees WHERE department_id = e.department_id) AS 部门薪资水平 FROM employees e; -- 子查询按部门平均薪资判断等级,作为员工记录的列 

144、子查询与字符串函数

子查询中使用字符串处理函数

SELECT * FROM customers WHERE name LIKE (SELECT CONCAT('%', city, '%') FROM locations WHERE id = customers.location_id); -- 子查询返回客户所在城市并拼接为模糊匹配模式,主查询返回姓名包含城市名的客户 

145、子查询返回空集处理

处理子查询返回空集的情况(避免结果异常)

SELECT * FROM employees WHERE salary > COALESCE((SELECT AVG(salary) FROM employees WHERE department_id = 99), 0); -- 若99部门不存在(子查询返回NULL),用COALESCE设为0,避免主查询无结果 

七、分页查询

146、LIMIT基础分页(MySQL)

限制返回的行数(适合简单分页)

SELECT * FROM products LIMIT 10; -- 返回前10条商品记录(第1-10条),适合首页展示 

147、LIMIT + OFFSET分页(MySQL)

从指定位置开始返回指定行数(标准分页)

SELECT * FROM products ORDER BY id ASC LIMIT 10 OFFSET 20; -- 从第21条开始,返回10条记录(第21-30条),OFFSET为跳过的行数 

148、分页公式(页码计算)

根据页码和每页条数计算OFFSET

-- 页码page=3,每页10条:(3-1)*10=20 → OFFSET 20 SELECT * FROM products ORDER BY id LIMIT 10 OFFSET (3-1)*10; -- 通用分页公式:OFFSET = (页码-1)*每页条数 

149、分页+排序(必选)

确保分页结果顺序稳定(无排序可能导致分页错乱)

SELECT * FROM orders ORDER BY create_time DESC LIMIT 15 OFFSET 30; -- 先按创建时间降序,再取第31-45条订单,排序是分页的前提 

150、分页查询指定列

仅返回需要的列,提高分页效率

SELECT id, title, price FROM products ORDER BY id LIMIT 20 OFFSET 100; -- 分页时只查询必要字段,减少数据传输 

151、分页+条件筛选

对筛选后的结果进行分页

SELECT * FROM employees WHERE department_id = 30 ORDER BY salary DESC LIMIT 10 OFFSET 10; -- 先筛选30部门员工,排序后取第11-20条 

152、分页查询总条数(计算总页数)

查询符合条件的总记录数,计算总页数

-- 查数据 SELECT * FROM products WHERE price > 100 ORDER BY id LIMIT 10 OFFSET 0; -- 查总条数(计算总页数:CEIL(总条数/每页条数)) SELECT COUNT(*) AS total FROM products WHERE price > 100; -- 通常与分页查询配合使用,返回总记录数 

153、子查询分页

对派生表的结果进行分页

SELECT * FROM (SELECT id, name, salary*12 AS 年薪 FROM employees WHERE department_id = 30) AS dept30_emp ORDER BY 年薪 DESC LIMIT 5 OFFSET 0; -- 先子查询计算年薪,再对结果分页 

154、连接查询分页

对多表连接的结果进行分页

SELECT e.name, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.id ORDER BY e.id LIMIT 10 OFFSET 50; -- 连接查询后分页,避免返回过多数据 

155、偏移量过大优化(WHERE + 主键)

解决OFFSET过大导致的性能问题(适用于自增主键)

-- 传统方式(OFFSET大时慢) SELECT * FROM products ORDER BY id LIMIT 10 OFFSET ; -- 优化方式(用主键过滤代替OFFSET) SELECT * FROM products WHERE id >  ORDER BY id LIMIT 10; -- 假设id是自增主键,直接定位到上次分页的最后一个id,性能更优 

156、FETCH分页(SQL标准)

按SQL标准语法分页(PostgreSQL、SQL Server支持)

SELECT * FROM employees ORDER BY hire_date OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; -- 跳过20行,取接下来的10行,与LIMIT OFFSET功能相同 

157、分页+去重

对去重后的结果进行分页

SELECT DISTINCT category_id, category_name FROM products WHERE price < 500 ORDER BY category_id LIMIT 5 OFFSET 0; -- 先去重,再分页返回不重复的分类 

158、分页+聚合查询

对分组聚合后的结果进行分页

SELECT department_id, AVG(salary) AS 平均薪资 FROM employees GROUP BY department_id ORDER BY 平均薪资 DESC LIMIT 3 OFFSET 0; -- 分组计算后分页,取平均薪资最高的3个部门 

159、分页查询最后N条

查询最后N条记录(如:最新数据)

SELECT * FROM (SELECT * FROM orders ORDER BY create_time DESC LIMIT 100) AS last_100 ORDER BY create_time ASC; -- 先取最新100条,再按时间升序排列( oldest first ) 

160、分页查询随机数据

分页返回随机抽样数据

SELECT * FROM products ORDER BY RAND() LIMIT 5 OFFSET 0; -- 随机排序后取前5条,适合随机推荐(大数据量时性能差) 

八、条件逻辑(CASE)

161、简单CASE表达式

按字段值匹配返回对应结果(类似switch-case)

SELECT name, CASE department_id WHEN 10 THEN '行政部' WHEN 20 THEN '财务部' WHEN 30 THEN '销售部' ELSE '其他部门' END AS 部门名称 FROM employees; -- 按department_id的值匹配对应的部门名称,不匹配则返回"其他部门" 

162、搜索CASE表达式

按条件判断返回对应结果(类似if-else if-else)

SELECT name, salary, CASE WHEN salary > 10000 THEN '高薪' WHEN salary > 5000 THEN '中等' ELSE '基础' END AS 薪资等级 FROM employees; -- 按薪资范围判断等级,条件按顺序执行,满足即返回 

163、CASE在WHERE中

根据条件动态调整筛选逻辑

SELECT * FROM products WHERE price > CASE WHEN category_id = 1 THEN 500 WHEN category_id = 2 THEN 1000 ELSE 300 END; -- 不同分类的价格筛选阈值不同(分类1>500,分类2>1000,其他>300) 

164、CASE在GROUP BY中

按CASE结果分组统计

SELECT CASE WHEN salary > 8000 THEN '高薪群体' ELSE '普通群体' END AS 群体, COUNT(*) AS 人数 FROM employees GROUP BY 群体; -- 按薪资等级分组,统计两个群体的人数 

165、CASE在ORDER BY中

按CASE结果自定义排序

SELECT name, status FROM orders ORDER BY CASE status WHEN 'processing' THEN 1 WHEN 'shipped' THEN 2 WHEN 'delivered' THEN 3 ELSE 4 END; -- 按订单状态自定义排序:processing→shipped→delivered→其他 

166、CASE实现条件计数

统计满足特定条件的行数(类似SUM+条件)

SELECT department_id, COUNT(CASE WHEN gender = '男' THEN 1 END) AS 男性人数, COUNT(CASE WHEN gender = '女' THEN 1 END) AS 女性人数 FROM employees GROUP BY department_id; -- 按部门统计男女员工数量(COUNT忽略NULL,不满足条件时CASE返回NULL) 

167、CASE实现条件求和

对满足特定条件的字段求和

SELECT department_id, SUM(CASE WHEN gender = '男' THEN salary END) AS 男性总薪资, SUM(CASE WHEN gender = '女' THEN salary END) AS 女性总薪资 FROM employees GROUP BY department_id; -- 按部门计算男女员工的薪资总和 

168、CASE嵌套

在CASE表达式中嵌套另一个CASE

SELECT name, salary, CASE WHEN salary > 10000 THEN '高薪' ELSE CASE WHEN salary > 5000 THEN '中等' ELSE '基础' END END AS 薪资等级 FROM employees; -- 嵌套CASE实现多层条件判断(等价于单层多条件) 

169、CASE处理NULL值

用CASE将NULL值转换为指定内容

SELECT name, CASE WHEN manager_id IS NULL THEN '无经理' ELSE '有经理' END AS 经理状态 FROM employees; -- 将manager_id为NULL的记录标记为"无经理",否则为"有经理" 

170、CASE与日期函数结合

按日期条件分类

SELECT order_id, order_date, CASE WHEN order_date >= '2023-10-01' THEN 'Q4' WHEN order_date >= '2023-07-01' THEN 'Q3' WHEN order_date >= '2023-04-01' THEN 'Q2' ELSE 'Q1' END AS 季度 FROM orders WHERE YEAR(order_date) = 2023; -- 按订单日期划分2023年的季度 

171、CASE返回计算值

根据条件返回不同的计算结果

SELECT name, salary, CASE WHEN department_id = 30 THEN salary * 1.2 -- 销售部加薪20% WHEN department_id = 20 THEN salary * 1.1 -- 财务部加薪10% ELSE salary -- 其他部门薪资不变 END AS 调整后薪资 FROM employees; -- 按部门计算调整后的薪资 

172、CASE在HAVING中

在分组筛选中使用CASE结果

SELECT department_id, AVG(salary) AS 平均薪资 FROM employees GROUP BY department_id HAVING CASE WHEN department_id IN (10, 20) THEN AVG(salary) > 6000 -- 部门10、20要求平均>6000 ELSE AVG(salary) > 5000 -- 其他部门要求平均>5000 END; -- 不同部门的分组筛选条件不同 

173、CASE与聚合函数结合

对聚合结果进行条件判断

SELECT CASE WHEN AVG(salary) > 8000 THEN '高薪资部门' ELSE '普通薪资部门' END AS 部门类型, COUNT(*) AS 部门数量 FROM employees GROUP BY department_id; -- 按部门平均薪资判断部门类型,统计各类型的部门数量 

174、CASE实现行转列

将行数据转换为列(交叉表)

SELECT department_id, SUM(CASE WHEN gender = '男' THEN 1 ELSE 0 END) AS 男, SUM(CASE WHEN gender = '女' THEN 1 ELSE 0 END) AS 女 FROM employees GROUP BY department_id; -- 将性别行数据转为列,显示每个部门的男女数量 

175、CASE与字符串函数结合

按条件处理字符串

SELECT name, CASE WHEN LENGTH(name) > 4 THEN CONCAT(SUBSTRING(name, 1, 2), '*') -- 长名字脱敏 ELSE name -- 短名字不处理 END AS 脱敏姓名 FROM users; -- 对长度>4的姓名进行脱敏处理(如:"张三丰"→"张*") 

九、组合查询(UNION, INTERSECT, EXCEPT)

176、UNION合并结果(去重)

合并两个查询结果,自动去除重复行

SELECT name, '员工' AS 类型 FROM employees UNION SELECT name, '客户' AS 类型 FROM customers; -- 合并员工和客户的姓名,去重后返回,两查询列数和类型需一致 

177、UNION ALL合并结果(保留重复)

合并两个查询结果,保留所有重复行(性能优于UNION)

SELECT product_id FROM order_items WHERE order_id = 100 UNION ALL SELECT product_id FROM order_items WHERE order_id = 101; -- 合并两个订单的商品ID,保留重复项(如:两订单都包含的商品) 

178、多表UNION(3个及以上)

合并多个查询结果

SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 UNION ALL SELECT id, name FROM table3; -- 合并3个表的id和name字段,保留所有行 

179、UNION与条件筛选

合并不同条件的查询结果

SELECT * FROM products WHERE price < 100 AND category_id = 1 UNION SELECT * FROM products WHERE price > 1000 AND category_id = 2; -- 合并1类低价商品和2类高价商品的结果 

180、UNION与排序

对合并后的结果进行排序(需加括号)

(SELECT name, salary FROM employees WHERE department_id = 30) UNION (SELECT name, salary FROM employees WHERE salary > 10000) ORDER BY salary DESC; -- 合并30部门员工和高薪员工,整体按薪资降序(排序对合并后结果生效) 

181、UNION模拟全外连接(MySQL)

在不支持FULL JOIN的数据库中模拟全外连接

SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id UNION SELECT e.name, d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id; -- 左连接+右连接+UNION,等价于全外连接 

182、INTERSECT取交集(PostgreSQL/Oracle)

返回两个查询结果的共同行(交集)

SELECT product_id FROM products WHERE price > 500 INTERSECT SELECT product_id FROM order_items; -- 返回价格>500且被订购过的商品ID(两结果的交集) 

183、MySQL模拟INTERSECT(INNER JOIN)

在MySQL中用内连接模拟交集查询

-- 等价于INTERSECT SELECT p.product_id FROM (SELECT product_id FROM products WHERE price > 500) p INNER JOIN (SELECT product_id FROM order_items) oi ON p.product_id = oi.product_id; -- 两子查询结果内连接,得到交集 

184、INTERSECT ALL(保留重复交集)

返回交集并保留重复行(重复次数取两结果中的最小值)

SELECT product_id FROM order_items WHERE order_id = 100 INTERSECT ALL SELECT product_id FROM order_items WHERE order_id = 101; -- 返回两订单都包含的商品ID,重复次数为两订单中较少的出现次数 

185、EXCEPT取差集(PostgreSQL)

返回第一个查询有而第二个查询没有的行(差集)

SELECT product_id FROM products EXCEPT SELECT product_id FROM order_items; -- 返回所有商品中未被订购的商品ID(商品表有,订单项表无) 

186、MINUS取差集(Oracle)

Oracle中实现差集查询(等价于EXCEPT)

SELECT product_id FROM products MINUS SELECT product_id FROM order_items; -- Oracle专用,功能同EXCEPT,返回未被订购的商品ID 

187、MySQL模拟EXCEPT(LEFT JOIN + IS NULL)

在MySQL中用左连接模拟差集查询

-- 等价于EXCEPT SELECT p.product_id FROM (SELECT product_id FROM products) p LEFT JOIN (SELECT product_id FROM order_items) oi ON p.product_id = oi.product_id WHERE oi.product_id IS NULL; -- 左连接后筛选右表为NULL的行,即差集 

188、EXCEPT ALL(保留重复差集)

返回差集并保留重复行(重复次数为第一个查询减去第二个查询的次数)

SELECT tag FROM article_tags WHERE article_id = 1 EXCEPT ALL SELECT tag FROM article_tags WHERE article_id = 2; -- 返回文章1有而文章2没有的标签,保留重复次数 

189、组合查询+排序(统一排序)

对多个查询的合并结果进行统一排序

(SELECT '员工' AS 类型, name, hire_date AS 日期 FROM employees) UNION ALL (SELECT '客户' AS 类型, name, register_date AS 日期 FROM customers) ORDER BY 日期 DESC; -- 合并员工和客户数据,按日期统一降序(最新记录在前) 

190、组合查询+限制行数

对合并结果限制总返回行数

(SELECT name FROM employees WHERE department_id = 30) UNION ALL (SELECT name FROM customers WHERE country = 'China') LIMIT 20; -- 合并结果后只返回前20行 

191、组合查询中的NULL处理

UNION中NULL视为相同值(去重时会合并)

SELECT NULL AS col FROM dual UNION SELECT NULL AS col FROM dual; -- 结果只返回1行NULL(UNION去重,视NULL为相同) 

192、组合查询与列别名

为组合查询的列统一指定别名(以第一个查询为准)

SELECT id, name AS 名称 FROM employees UNION SELECT customer_id, customer_name FROM customers; -- 第一个查询指定别名为"名称",合并结果列名为"名称" 

十、窗口函数(Window Functions)

193、排名函数(ROW_NUMBER)

为每行分配唯一序号(同组内不重复,即使值相同)

SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS 薪资排名 FROM employees; -- 按薪资降序排序,为每个员工分配唯一排名(1,2,3...,相同薪资也按顺序排) 

194、排名函数(RANK)

排名相同则序号相同,后续序号跳过(如:1,2,2,4…)

SELECT name, salary, RANK() OVER (ORDER BY salary DESC) AS 薪资排名 FROM employees; -- 薪资相同则排名相同,下一名次跳过(如:两个第2名,接下来是第4名) 

195、排名函数(DENSE_RANK)

排名相同则序号相同,后续序号连续(如:1,2,2,3…)

SELECT name, salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS 薪资排名 FROM employees; -- 薪资相同则排名相同,下一名次连续(如:两个第2名,接下来是第3名) 

196、分区排名(PARTITION BY)

按指定列分区,在每个分区内单独排名

SELECT name, department_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS 部门内薪资排名 FROM employees; -- 按部门分区,每个部门内按薪资降序排名(每个部门的排名从1开始) 

197、聚合窗口函数(SUM OVER)

计算窗口内的累计和(不聚合行,保留每行记录)

SELECT order_id, amount, SUM(amount) OVER (ORDER BY order_date) AS 累计销售额 FROM orders; -- 按订单日期排序,计算到当前行为止的累计销售额(每行都显示累计值) 

198、分区聚合(SUM OVER PARTITION)

按分区计算聚合值(每个分区内的总和)

SELECT name, department_id, salary, SUM(salary) OVER (PARTITION BY department_id) AS 部门总薪资 FROM employees; -- 按部门分区,显示每个员工所属部门的总薪资(同部门员工显示相同值) 

199、移动平均(AVG OVER 窗口帧)

计算指定窗口范围内的平均值(如:前N行到当前行)

SELECT order_date, amount, AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS 近3天平均 FROM daily_sales; -- 按日期排序,计算当前行及前2行(共3行)的平均销售额(移动平均) 

200、前后行取值(LAG)

获取当前行之前第N行的字段值

SELECT order_id, order_date, LAG(order_date, 1) OVER (ORDER BY order_date) AS 上一订单日期 FROM orders; -- 按日期排序,获取当前订单的上一个订单日期(第一行返回NULL) 

201、前后行取值(LEAD)

获取当前行之后第N行的字段值

SELECT order_id, order_date, LEAD(order_date, 1) OVER (ORDER BY order_date) AS 下一订单日期 FROM orders; -- 按日期排序,获取当前订单的下一个订单日期(最后一行返回NULL) 

202、首行/末行取值(FIRST_VALUE/LAST_VALUE)

获取窗口内的第一行或最后一行的字段值

SELECT name, salary, FIRST_VALUE(name) OVER (ORDER BY salary DESC) AS 最高薪员工, LAST_VALUE(name) OVER (ORDER BY salary DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS 最低薪员工 FROM employees; -- 第一列显示最高薪员工(全表),第二列显示最低薪员工(需指定完整窗口范围) 

203、分箱函数(NTILE)

将数据按指定数量分组(分箱),返回组编号

SELECT name, salary, NTILE(4) OVER (ORDER BY salary DESC) AS 薪资等级 FROM employees; -- 按薪资降序排序,将员工分为4组(等级1-4),每组数量尽量平均 

204、窗口函数+筛选(子查询)

对窗口函数的结果进行筛选(窗口函数不能直接用在WHERE中)

SELECT * FROM ( SELECT name, department_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS 部门排名 FROM employees ) t WHERE 部门排名 = 1; -- 子查询计算部门内排名,主查询筛选出每个部门的第一名 

205、多窗口函数组合

在同一查询中使用多个窗口函数

SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS 全局序号, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS 部门排名, AVG(salary) OVER (PARTITION BY department_id) AS 部门平均薪资 FROM employees; -- 同时显示全局序号、部门排名和部门平均薪资 

206、窗口帧范围(ROWS)

按行数定义窗口范围(物理行)

SELECT date, sales, SUM(sales) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 三天总和 FROM daily_sales; -- 窗口范围为当前行、前1行和后1行(共3行),计算销售额总和 

207、窗口帧范围(RANGE)

按值范围定义窗口范围(逻辑范围,适用于数值/日期)

SELECT salary, COUNT(*) OVER (ORDER BY salary RANGE BETWEEN 1000 PRECEDING AND 1000 FOLLOWING) AS 相近薪资人数 FROM employees; -- 统计与当前薪资相差±1000范围内的员工数量 

208、窗口帧起点(UNBOUNDED PRECEDING)

窗口范围从第一行到当前行

SELECT month, sales, SUM(sales) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 累计销售额 FROM monthly_sales; -- 计算从第一行到当前行的累计销售额(按月份递增) 

209、百分比排名(PERCENT_RANK)

计算当前行的相对排名百分比((排名-1)/(总行数-1))

SELECT name, salary, PERCENT_RANK() OVER (ORDER BY salary DESC) AS 薪资百分比排名 FROM employees; -- 返回0-1之间的百分比,值越小排名越靠前(最高薪为0,最低薪为1) 

210、累积分布(CUME_DIST)

计算当前行及之前行的行数占总行数的比例

SELECT name, salary, CUME_DIST() OVER (ORDER BY salary DESC) AS 累积分布 FROM employees; -- 表示薪资大于等于当前行的员工占比(如:0.3表示30%的员工薪资≥当前值) 

211、NTH_VALUE函数

返回窗口内第N行的指定字段值

SELECT name, salary, NTH_VALUE(name, 3) OVER (ORDER BY salary DESC) AS 第三名薪资员工 FROM employees; -- 按薪资降序,显示第三名员工的姓名(所有行都显示该值) 

212、窗口函数与CASE结合

在窗口函数中使用条件逻辑

SELECT name, department_id, salary, SUM(CASE WHEN gender = '男' THEN 1 ELSE 0 END) OVER (PARTITION BY department_id) AS 部门男性人数 FROM employees; -- 按部门分区,计算每个部门的男性员工数量 

213、窗口函数排序方向

指定窗口函数的排序方向(升序/降序)

SELECT name, hire_date, ROW_NUMBER() OVER (ORDER BY hire_date ASC) AS 入职顺序 FROM employees; -- 按入职日期升序(最早入职在前),分配入职顺序号 

214、多字段分区

按多个字段组合分区

SELECT name, department_id, job_id, salary, RANK() OVER (PARTITION BY department_id, job_id ORDER BY salary DESC) AS 岗位内排名 FROM employees; -- 按部门和岗位组合分区,每个分区内按薪资排名 

215、窗口函数与聚合函数区别

对比窗口函数与普通聚合函数(窗口函数不合并行)

-- 普通聚合(合并行) SELECT department_id, AVG(salary) AS 部门平均 FROM employees GROUP BY department_id; -- 窗口函数(保留所有行) SELECT name, department_id, salary, AVG(salary) OVER (PARTITION BY department_id) AS 部门平均 FROM employees; -- 每行都显示部门平均薪资,不合并行 

216、窗口函数计算差异

计算当前行与某行的差值(如:与首行/前一行)

SELECT month, sales, sales - FIRST_VALUE(sales) OVER (ORDER BY month) AS 与首月差异, sales - LAG(sales, 1) OVER (ORDER BY month) AS 与上月差异 FROM monthly_sales; -- 计算每月销售额与首月、上月的差值 

217、窗口函数实现分页

用ROW_NUMBER()实现分页查询

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM products ) t WHERE rn BETWEEN 21 AND 30; -- 子查询生成行号,主查询筛选21-30行(分页) 

218、窗口函数去重

按分区取每组的第一条记录(去重)

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY hire_date) AS rn FROM employees ) t WHERE rn = 1; -- 按部门分区,取每个部门最早入职的员工(每组第一条) 

219、窗口函数计算占比

计算当前行值占分区总和的比例

SELECT name, department_id, salary, salary / SUM(salary) OVER (PARTITION BY department_id) AS 薪资占比 FROM employees; -- 计算每个员工薪资占其部门总薪资的比例 

220、窗口函数嵌套

窗口函数结果作为其他函数的参数

SELECT name, salary, ROUND(AVG(salary) OVER (ORDER BY salary), 2) AS 平均薪资(保留两位) FROM employees; -- 对窗口函数计算的平均薪资取两位小数 

十一、公用表表达式(CTE)

221、基础CTE(WITH子句)

定义临时结果集,增强查询可读性

WITH dept_avg AS ( SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id ) SELECT e.name, e.salary, da.avg_salary FROM employees e INNER JOIN dept_avg da ON e.department_id = da.department_id; -- 定义CTE计算部门平均薪资,主查询关联使用 

222、多CTE定义

同时定义多个CTE,用逗号分隔

WITH dept_avg AS (SELECT department_id, AVG(salary) AS avg_sal FROM employees GROUP BY department_id), dept_max AS (SELECT department_id, MAX(salary) AS max_sal FROM employees GROUP BY department_id) SELECT da.department_id, da.avg_sal, dm.max_sal FROM dept_avg da INNER JOIN dept_max dm ON da.department_id = dm.department_id; -- 定义两个CTE(部门平均和最高薪资),主查询关联获取结果 

223、CTE嵌套

在CTE中引用另一个CTE

WITH dept_total AS (SELECT department_id, SUM(salary) AS total_sal FROM employees GROUP BY department_id), company_total AS (SELECT SUM(total_sal) AS company_sal FROM dept_total) -- 引用dept_total SELECT dt.department_id, dt.total_sal / ct.company_sal AS 部门薪资占比 FROM dept_total dt, company_total ct; -- 内层CTE依赖外层CTE,计算部门薪资占公司总薪资比例 

224、CTE与窗口函数结合

用CTE简化窗口函数查询

WITH ranked_emp AS ( SELECT name, department_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank FROM employees ) SELECT * FROM ranked_emp WHERE dept_rank <= 3; -- CTE计算部门内排名,主查询筛选前三名 

225、递归CTE(层级数据)

处理树形/层级结构数据(如:组织结构)

WITH RECURSIVE org_tree AS ( -- 初始查询(根节点) SELECT id, name, parent_id, 1 AS level FROM departments WHERE parent_id IS NULL UNION ALL -- 递归查询(子节点) SELECT d.id, d.name, d.parent_id, ot.level + 1 AS level FROM departments d INNER JOIN org_tree ot ON d.parent_id = ot.id ) SELECT * FROM org_tree ORDER BY level, id; -- 递归查询部门层级结构,level表示层级深度 

226、递归CTE计算累积和

用递归CTE实现累积求和(替代窗口函数)

WITH RECURSIVE sales_cte AS ( -- 初始查询(第一行) SELECT date, amount, amount AS cumulative_sum, ROW_NUMBER() OVER (ORDER BY date) AS rn FROM daily_sales WHERE rn = 1 UNION ALL -- 递归查询(后续行) SELECT ds.date, ds.amount, sc.cumulative_sum + ds.amount, ds.rn FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY date) AS rn FROM daily_sales) ds INNER JOIN sales_cte sc ON ds.rn = sc.rn + 1 ) SELECT date, amount, cumulative_sum FROM sales_cte; -- 递归计算每日销售额的累积和 

227、CTE与分页结合

用CTE简化分页查询

WITH cte AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM products ) SELECT * FROM cte WHERE rn BETWEEN 11 AND 20; -- CTE生成行号,主查询筛选第11-20行(分页) 

228、CTE与UPDATE结合

用CTE更新表数据(部分数据库支持)

WITH dept_avg AS ( SELECT department_id, AVG(salary) AS avg_sal FROM employees GROUP BY department_id ) UPDATE employees e SET salary = e.salary * 1.1 WHERE e.salary < (SELECT avg_sal FROM dept_avg da WHERE da.department_id = e.department_id); -- 用CTE结果更新低于部门平均薪资的员工(涨10%) 

229、CTE与DELETE结合

用CTE删除表数据

WITH old_orders AS ( SELECT id FROM orders WHERE order_date < '2020-01-01' ) DELETE FROM orders WHERE id IN (SELECT id FROM old_orders); -- 删除2020年以前的订单,用CTE筛选目标ID 

230、CTE中的DISTINCT

在CTE中去重

WITH unique_categories AS ( SELECT DISTINCT category_id, category_name FROM products WHERE price > 1000 ) SELECT * FROM unique_categories ORDER BY category_id; -- CTE筛选价格>1000的商品的不重复分类 

231、CTE中的条件逻辑

在CTE中使用CASE表达式

WITH salary_level AS ( SELECT name, salary, CASE WHEN salary > 10000 THEN 'A' WHEN salary > 5000 THEN 'B' ELSE 'C' END AS level FROM employees ) SELECT level, COUNT(*) AS 人数 FROM salary_level GROUP BY level; -- CTE按薪资分级,主查询统计各级人数 

232、CTE与JOIN结合

多表连接结果作为CTE

WITH emp_dept AS ( SELECT e.name, d.department_name, e.salary FROM employees e INNER JOIN departments d ON e.department_id = d.id ) SELECT department_name, AVG(salary) AS 平均薪资 FROM emp_dept GROUP BY department_name; -- CTE存储连接结果,主查询计算平均薪资 

233、CTE的多次引用

在主查询中多次引用同一CTE

WITH dept_stats AS ( SELECT department_id, AVG(salary) AS avg_sal, MAX(salary) AS max_sal FROM employees GROUP BY department_id ) SELECT (SELECT COUNT(*) FROM dept_stats WHERE avg_sal > 8000) AS 高平均部门数, (SELECT COUNT(*) FROM dept_stats WHERE max_sal > 15000) AS 有高薪部门数; -- 两次引用CTE,统计不同条件的部门数 

234、CTE中的聚合与筛选

在CTE中先聚合再筛选

WITH high_depts AS ( SELECT department_id, AVG(salary) AS avg_sal FROM employees GROUP BY department_id HAVING AVG(salary) > 7000 ) SELECT e.name, e.salary, hd.avg_sal FROM employees e INNER JOIN high_depts hd ON e.department_id = hd.department_id; -- CTE筛选平均薪资>7000的部门,主查询关联员工 

235、CTE与日期处理

在CTE中处理日期数据

WITH monthly_sales AS ( SELECT YEAR(order_date) AS 年, MONTH(order_date) AS 月, SUM(amount) AS 销售额 FROM orders GROUP BY 年, 月 ) SELECT 年, 月, 销售额 FROM monthly_sales WHERE 年 = 2023 ORDER BY 月; -- CTE按年月统计销售额,主查询筛选2023年数据 

十二、元数据查询

236、查询表结构(DESCRIBE)

查看表的字段信息(MySQL简洁方式)

DESCRIBE employees; -- 显示employees表的字段名、类型、是否为NULL、键信息等 -- 简写 DESC employees; -- 与DESCRIBE功能相同 

237、查询表结构(INFORMATION_SCHEMA)

通过系统表查询表结构(标准方式,支持多数据库)

SELECT COLUMN_NAME AS 列名, DATA_TYPE AS 数据类型, IS_NULLABLE AS 是否允许NULL, COLUMN_KEY AS 键类型 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'employees' AND TABLE_SCHEMA = 'company_db'; -- 查询指定库(company_db)中表(employees)的字段详情 

238、查询数据库中的表(SHOW TABLES)

列出当前数据库中的所有表(MySQL)

SHOW TABLES; -- 显示当前数据库的所有表名 

239、查询数据库中的表(INFORMATION_SCHEMA)

通过系统表查询数据库中的表(标准方式)

SELECT TABLE_NAME AS 表名 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'company_db' AND TABLE_TYPE = 'BASE TABLE'; -- 列出company_db库中的所有基表(排除视图) 

240、查询表的索引(SHOW INDEX)

查看表的所有索引信息(MySQL)

SHOW INDEX FROM employees; -- 显示employees表的所有索引,包括索引名、列名、索引类型等 

241、查询表的索引(INFORMATION_SCHEMA)

通过系统表查询索引信息(标准方式)

SELECT INDEX_NAME AS 索引名, COLUMN_NAME AS 索引列, INDEX_TYPE AS 索引类型 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'employees' AND TABLE_SCHEMA = 'company_db'; -- 查询employees表的索引详情 

242、查询视图定义(SHOW CREATE VIEW)

查看视图的创建语句(MySQL)

SHOW CREATE VIEW employee_view; -- 显示employee_view视图的完整创建SQL语句 

243、查询视图定义(INFORMATION_SCHEMA)

通过系统表查询视图定义(标准方式)

SELECT VIEW_DEFINITION AS 视图定义 FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = 'employee_view' AND TABLE_SCHEMA = 'company_db'; -- 查询employee_view视图的定义SQL 

244、查询外键关系(INFORMATION_SCHEMA)

查询表的外键约束信息

SELECT COLUMN_NAME AS 外键列, REFERENCED_TABLE_NAME AS 参考表, REFERENCED_COLUMN_NAME AS 参考列 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'employees' AND TABLE_SCHEMA = 'company_db' AND REFERENCED_TABLE_NAME IS NOT NULL; -- 查询employees表的外键关联(关联的表和列) 

245、查询存储过程列表(SHOW PROCEDURE STATUS)

查看数据库中的存储过程(MySQL)

SHOW PROCEDURE STATUS WHERE Db = 'company_db'; -- 显示company_db库中的所有存储过程信息 

246、查询存储过程定义(SHOW CREATE PROCEDURE)

查看存储过程的创建语句(MySQL)

SHOW CREATE PROCEDURE update_salary; -- 显示update_salary存储过程的完整创建代码 

247、查询触发器列表(SHOW TRIGGERS)

查看数据库中的触发器(MySQL)

SHOW TRIGGERS FROM company_db; -- 显示company_db库中的所有触发器信息 

248、查询表的大小(MySQL)

查看表的存储空间大小(数据+索引)

SELECT TABLE_NAME AS 表名, ROUND(DATA_LENGTH / 1024 / 1024, 2) AS 数据大小(MB), ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS 索引大小(MB) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'company_db' AND TABLE_NAME = 'employees'; -- 查询employees表的数据和索引大小(MB) 

249、查询数据库大小(MySQL)

计算整个数据库的存储空间大小

SELECT TABLE_SCHEMA AS 数据库名, ROUND(SUM(DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS 总大小(MB) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'company_db' GROUP BY TABLE_SCHEMA; -- 计算company_db库的总大小(数据+索引,单位MB) 

250、查询当前数据库连接(MySQL)

查看当前数据库的活跃连接

SHOW PROCESSLIST; -- 显示当前所有数据库连接的进程信息,包括ID、用户、状态等 

251、查询表的行数(近似值,MySQL)

快速获取表的行数(非精确值,来自统计信息)

SELECT TABLE_ROWS AS 近似行数 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'employees' AND TABLE_SCHEMA = 'company_db'; -- 快速获取employees表的近似行数(比COUNT(*)快) 

252、查询自增ID当前值(MySQL)

查看表的自增主键当前值

SELECT AUTO_INCREMENT AS 下一个自增值 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'employees' AND TABLE_SCHEMA = 'company_db'; -- 查看employees表下一个自增ID的值 

十三、现代数据库查询中的一些进阶场景

253、获取当前时间(带时区)

查询当前系统时间及不同时区的时间,用于时间戳记录或跨时区业务。

-- MySQL:获取当前系统时间(含日期和时间)及UTC标准时间 SELECT NOW() AS 当前系统时间, -- 格式:YYYY-MM-DD HH:MM:SS,受数据库时区影响 UTC_TIMESTAMP() AS UTC时间; -- 世界协调时间,不受时区影响 -- PostgreSQL:获取指定时区(如:上海)的当前时间 SELECT CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai' AS 上海时间; -- 显式指定时区,适用于跨国业务 

254、日期加减(INTERVAL)

对日期进行加减运算,计算未来或过去的时间点,常用在有效期、到期日计算。

-- 对当前日期进行加减操作(支持day、month、year、hour等单位) SELECT CURRENT_DATE + INTERVAL '3 days' AS 三天后日期, -- 当前日期加3天 CURRENT_DATE - INTERVAL '1 month' AS 一个月前日期, -- 当前日期减1个月 NOW() + INTERVAL '2 hours' AS 两小时后时间; -- 当前时间加2小时 -- 注:INTERVAL是标准SQL语法,MySQL、PostgreSQL、Oracle均支持 

255、获取当月第一天和最后一天

快速定位当月时间范围,用于月度数据统计(如:“本月销售额”)。

-- MySQL:获取当月第一天和最后一天 SELECT DATE_FORMAT(CURRENT_DATE, '%Y-%m-01') AS 当月第一天, -- 格式化当前日期为"年-月-01"(如:2023-10-01) LAST_DAY(CURRENT_DATE) AS 当月最后一天; -- 内置函数直接返回当月最后一天(如:2023-10-31) -- PostgreSQL:获取当月第一天 SELECT (DATE_TRUNC('MONTH', CURRENT_DATE))::DATE AS 当月第一天; -- 截断到月份的第一天 

256、按周统计(周一为周首)

按自然周(周一至周日)分组统计数据,符合国内业务习惯(区别于周日为周首的国际标准)。

-- 按周一为每周起点,统计每周订单数 SELECT -- 将订单日期转换为当周周一的日期(如:2023-10-12是周四,转换为2023-10-09) DATE_FORMAT(DATE_SUB(order_date, INTERVAL WEEKDAY(order_date) DAY), '%Y-%m-%d') AS 周一日期, COUNT(*) AS 周订单总数 -- 统计该周的订单数量 FROM orders GROUP BY 周一日期 -- 按周一日期分组 ORDER BY 周一日期; -- 按时间排序 -- 注:WEEKDAY函数返回0(周一)到6(周日)的数字,DATE_SUB减去对应天数得到周一 

257、字符串拆分(按分隔符转多行)

将单行中的分隔符字符串(如:逗号分隔的标签)拆分为多行,便于按标签统计或关联查询。

-- MySQL 8.0+:将文章表的标签字段(逗号分隔)拆分为多行 SELECT a.id AS 文章ID, -- 提取JSON数组中第n个元素并去除引号 JSON_UNQUOTE(JSON_EXTRACT(a.tags, CONCAT('$[', n, ']'))) AS 标签 FROM articles a, -- 生成数字序列(0、1、2),支持最多3个标签(可扩展更多行) (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2) AS nums -- 只提取数组中存在的元素(避免空值) WHERE JSON_LENGTH(a.tags) > n; -- 前提:tags字段需存储为JSON数组格式,如:["科技","教育","健康"] -- 若为普通字符串(如:"科技,教育,健康"),可先通过JSON_ARRAYAGG转换 

258、正则提取(REGEXP_SUBSTR)

从字符串中提取符合正则规则的子串(如:手机号、邮箱),用于数据清洗或信息提取。

-- 从用户评论的备注中提取11位手机号 SELECT id AS 评论ID, remark AS 原始备注, -- 正则匹配手机号:1开头,第2位3-9,后续9位数字(共11位) REGEXP_SUBSTR(remark, '1[3-9][0-9]{9}') AS 提取的手机号 FROM user_comments; -- 提取邮箱地址(简单匹配) SELECT REGEXP_SUBSTR(contact, '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}') AS 提取的邮箱 FROM customer_info; 

259、去除字符串前后空格(TRIM)

清洗字符串前后的空格或指定特殊字符(如:下划线、短横线),避免因格式问题导致的查询异常。

-- 去除姓名前后的空格 SELECT name AS 原始姓名, TRIM(BOTH ' ' FROM name) AS 清洗后姓名 -- BOTH表示同时去除前后空格(默认行为) FROM users WHERE name LIKE ' %' OR name LIKE '% '; -- 筛选明显有空格的记录 -- 去除前后的多种特殊字符(空格、下划线、短横线) SELECT TRIM(BOTH ' _-' FROM product_code) AS 清洗后编码 FROM products WHERE product_code LIKE '_%' OR product_code LIKE '%_'; -- 筛选带前缀/后缀特殊字符的记录 

260、分组内 Top N(每个部门薪资前三的员工)

在每个分组(如:部门)中筛选出排名前N的记录,用于业务中的“部门尖子生”、“区域Top3产品”等分析。

-- 用窗口函数实现每个部门薪资前三的员工查询 WITH ranked_emp AS ( SELECT name AS 员工姓名, department_id AS 部门ID, salary AS 薪资, -- 按部门分区,薪资降序排名(相同薪资不跳号) DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS 部门内排名 FROM employees ) -- 筛选排名前三的员工 SELECT 员工姓名, 部门ID, 薪资, 部门内排名 FROM ranked_emp WHERE 部门内排名 <= 3 ORDER BY 部门ID, 部门内排名; -- 注:若需严格唯一排名(相同薪资按顺序排),可替换为ROW_NUMBER() 

261、累计占比(帕累托分析)

计算数据按某维度排序后的累计占比,用于帕累托分析(如:“20%的商品贡献80%的销售额”)。

-- 分析商品销售额的累计占比,识别核心商品 WITH product_sales AS ( -- 计算每个商品的总销售额 SELECT product_id AS 商品ID, SUM(amount) AS 销售额 FROM sales GROUP BY product_id ), sorted_sales AS ( SELECT 商品ID, 销售额, -- 按销售额降序计算累计销售额占比 SUM(销售额) OVER (ORDER BY 销售额 DESC) / SUM(销售额) OVER () AS 累计占比 FROM product_sales ) -- 筛选贡献80%销售额的核心商品 SELECT 商品ID, 销售额, ROUND(累计占比 * 100, 2) AS 累计占比(%) FROM sorted_sales WHERE 累计占比 <= 0.8 ORDER BY 销售额 DESC; 

262、同比/环比计算

计算时间序列数据的同比(与去年同期比)和环比(与上一期比)增长率,用于业务趋势分析。

-- 按月统计销售额,并计算同比和环比增长率 WITH monthly_sales AS ( -- 按月聚合销售额 SELECT YEAR(order_date) AS 年, MONTH(order_date) AS 月, SUM(amount) AS 销售额 FROM orders GROUP BY 年, 月 ) SELECT 年, 月, 销售额, -- 同比:(今年当月 - 去年同月) / 去年同月 * 100% ROUND( (销售额 - LAG(销售额, 12) OVER (ORDER BY 年, 月)) / NULLIF(LAG(销售额, 12) OVER (ORDER BY 年, 月), 0) * 100, 2 ) AS 同比增长率(%), -- 环比:(本月 - 上月) / 上月 * 100% ROUND( (销售额 - LAG(销售额, 1) OVER (ORDER BY 年, 月)) / NULLIF(LAG(销售额, 1) OVER (ORDER BY 年, 月), 0) * 100, 2 ) AS 环比增长率(%) FROM monthly_sales ORDER BY 年, 月; -- 注:NULLIF避免除数为0,LAG(...,12)取12行前的数据(去年同月) 

263、查询JSON字段中的值

从JSON类型字段中提取指定键的值,适用于存储灵活结构数据(如:用户画像、商品属性)的场景。

-- MySQL:查询用户信息JSON字段中的详细信息 SELECT id AS 用户ID, user_info->'$.phone' AS 手机号_raw, -- 直接提取(带引号) JSON_UNQUOTE(user_info->'$.phone') AS 手机号, -- 去引号 user_info->'$.address.city' AS 城市_raw, -- 提取嵌套JSON的键 JSON_UNQUOTE(user_info->'$.address.city') AS 城市 -- 嵌套提取并去引号 FROM users; -- 前提:user_info字段为JSON类型,格式如:{"phone":"","address":{"city":"北京"}} -- PostgreSQL:更简洁的JSON提取语法 SELECT id AS 用户ID, user_info->>'phone' AS 手机号, -- ->>直接返回去引号的字符串 user_info->'address'->>'city' AS 城市 -- 链式提取嵌套键 FROM users; 

264、JSON数组查询(判断包含元素)

查询JSON数组中包含指定元素的记录,适用于标签、权限等多值场景。

-- MySQL:查询标签包含“促销”的文章 SELECT id AS 文章ID, title AS 标题, tags AS 标签列表 FROM articles -- JSON_CONTAINS判断JSON数组是否包含指定元素 WHERE JSON_CONTAINS(tags, JSON_ARRAY('促销')); -- 前提:tags字段为JSON数组格式,如:["促销","新品","限时折扣"] -- PostgreSQL:使用@>运算符判断数组包含关系 SELECT id AS 文章ID, title AS 标题, tags AS 标签列表 FROM articles WHERE tags @> '["促销"]'::JSONB; -- JSONB类型支持高效的包含判断 

265、查看SQL执行计划

分析SQL语句的执行计划,判断是否使用索引、表连接方式等,用于优化查询性能。

-- MySQL:查看查询执行计划(不实际执行查询) EXPLAIN SELECT * FROM employees WHERE department_id = 30 AND salary > 5000; -- 关键字段说明: -- type:连接类型(const > eq_ref > ref > range > ALL,ALL表示全表扫描,需优化) -- key:实际使用的索引(NULL表示未使用索引) -- rows:预计扫描的行数(值越小越好) -- PostgreSQL:查看执行计划并包含实际执行统计(会执行查询) EXPLAIN ANALYZE SELECT * FROM orders WHERE order_date > '2023-01-01'; -- 可查看实际扫描行数、执行时间等,更精准地定位性能瓶颈 

266、查询表中重复数据(并去重)

识别表中重复记录(如:重复的用户信息),并删除冗余数据,保证数据唯一性。

-- 1. 查找name和email都重复的用户(复合重复) SELECT name AS 姓名, email AS 邮箱, COUNT(*) AS 重复次数 FROM users GROUP BY name, email HAVING COUNT(*) > 1; -- 筛选重复次数大于1的记录 -- 2. 删除重复数据(保留ID最小的记录) DELETE FROM users WHERE id NOT IN ( -- 子查询获取每组重复记录中ID最小的记录 SELECT MIN(id) FROM users GROUP BY name, email ); -- 执行前建议备份数据,或先执行SELECT确认待删除的记录 

267、生成连续日期序列

生成指定范围内的连续日期,用于填充报表中缺失的日期(如:“某天无订单仍显示0”)。

-- MySQL:生成2023年10月1日至2023年10月31日的所有日期 WITH RECURSIVE date_series AS ( SELECT '2023-10-01' AS dt -- 起始日期 UNION ALL -- 递归加1天,直到结束日期 SELECT DATE_ADD(dt, INTERVAL 1 DAY) FROM date_series WHERE dt < '2023-10-31' -- 结束日期 ) SELECT dt AS 连续日期 FROM date_series; -- 应用:统计每天订单数(含无订单的日期) SELECT ds.dt AS 日期, COALESCE(COUNT(o.id), 0) AS 订单数 -- 无订单时显示0 FROM date_series ds LEFT JOIN orders o ON DATE(o.order_date) = ds.dt GROUP BY ds.dt ORDER BY ds.dt; 

268、行转列(动态列名,适用于报表)

将按行存储的时间序列数据(如:每月销售额)转换为列(如:1月、2月…),便于生成矩阵式报表。

-- 将2023年各商品的月度销售额转为列(1月至12月) SELECT product_id AS 商品ID, -- 用MAX+CASE将月份行转为列(SUM适用于多记录,MAX适用于单记录) MAX(CASE WHEN 月 = 1 THEN 销售额 END) AS 1月销售额, MAX(CASE WHEN 月 = 2 THEN 销售额 END) AS 2月销售额, MAX(CASE WHEN 月 = 3 THEN 销售额 END) AS 3月销售额, -- 省略4-11月... MAX(CASE WHEN 月 = 12 THEN 销售额 END) AS 12月销售额 FROM ( -- 子查询按月聚合销售额 SELECT product_id, MONTH(order_date) AS 月, SUM(amount) AS 销售额 FROM orders WHERE YEAR(order_date) = 2023 -- 限定年份 GROUP BY product_id, 月 ) AS monthly_data GROUP BY product_id ORDER BY product_id; 

269、查询树状结构的所有子节点(递归CTE)

查询树形结构中某节点的所有子节点(含多级子节点),适用于部门层级、分类目录等场景。

-- 查询部门ID=1的所有子部门(含一级、二级、三级...子部门) WITH RECURSIVE dept_tree AS ( -- 起始查询:根节点(部门ID=1) SELECT id AS 部门ID, name AS 部门名称, parent_id AS 父部门ID FROM departments WHERE id = 1 UNION ALL -- 递归查询:通过父部门ID关联子部门 SELECT d.id AS 部门ID, d.name AS 部门名称, d.parent_id AS 父部门ID FROM departments d -- 关联CTE中的已有节点,获取其子节点 INNER JOIN dept_tree dt ON d.parent_id = dt.部门ID ) -- 输出所有子节点(含根节点) SELECT * FROM dept_tree ORDER BY 父部门ID, 部门ID; -- 若需排除根节点,可在最后加WHERE 部门ID != 1 

以上269条常用SQL查询语句涵盖了数据查询语言(DQL)的大部分场景,包括基础查询、条件筛选、排序、聚合、连接、子查询、分页、条件逻辑、组合查询、窗口函数、CTE及元数据查询等等,我们日常干活能用到的场景基本都覆盖到了,可满足我们日常SQL查询需求。我们平时查数据、做统计,有了这些“模板”在手,基本不用愁了。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/189101.html

(0)
上一篇 2025-09-28 12:45
下一篇 2025-09-28 13:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信