1. 引言
在数据库操作中,SQL(Structured Query Language)是进行数据查询、操作和管理的核心语言。无论是简单的数据检索还是复杂的数据分析,掌握 SQL 查询语句和内置函数的使用都至关重要。本文将以 MySQL 数据库为例,通过一系列实际案例,深入讲解条件查询、排序查询以及常用函数的使用方法,帮助读者从基础到进阶全面掌握 SQL 查询技巧。
2. 条件查询详解
条件查询是 SQL 中最基础也是最常用的操作之一,它允许我们根据特定条件从表中筛选出所需的数据。WHERE 子句是实现条件查询的关键,支持多种运算符和逻辑组合。
2.1 IN 运算符的使用
IN 运算符用于指定多个可能的值,比使用多个 OR 运算符更加简洁高效。其基本语法为:WHERE column_name IN (value1, value2, ...)。
sql
-- 示例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES 中的一个员工名和工种编号
/* 分析:
查询的表:employees
查询的字段:first_name, job_id
查询的条件:job_id in ('IT_PROG','AD_VP','AD_PRES')
等价于:job_id = 'IT_PROG' OR job_id = 'AD_VP' OR job_id = 'AD_PRES'
*/
SELECT
first_name,
job_id
FROM
employees
WHERE
job_id IN ('IT_PROG','AD_VP','AD_PRES');
使用 IN 运算符的优势:
- 代码简洁:避免重复书写多个 OR 条件
- 可读性强:逻辑表达更加清晰直观
- 性能优化:在某些情况下,数据库优化器能更好地处理 IN 查询
2.2 NULL 值处理
NULL 在数据库中表示缺失或未知的值,处理 NULL 值需要特别注意,因为 NULL 与任何值的比较(包括 NULL 自身)都会返回 NULL,而不是 TRUE 或 FALSE。
sql
-- 示例:查询没有奖金率的员工名和奖金率
/* 分析:
查询的表:employees
查询的字段:first_name, commission_pct
查询的条件:commission_pct IS NULL
*/
SELECT
first_name,
commission_pct
FROM
employees
WHERE
commission_pct IS NULL;
重要提醒:不能使用等号(=)判断 NULL 值。以下查询是错误的:
sql
-- 错误示例:查询 salary 等于 12000 的员工
-- SELECT first_name, commission_pct
-- FROM employees
-- WHERE salary IS 12000; -- 这是错误的语法!
2.3 安全等于运算符(<=>)
MySQL 提供了安全等于运算符 <=>,它可以同时处理 NULL 值和普通数值的比较。
sql
-- 使用安全等于运算符查询没有奖金率的员工
SELECT
first_name,
commission_pct
FROM
employees
WHERE
commission_pct <=> NULL;
-- 安全等于运算符也可以用于普通数值的比较
SELECT
*
FROM
employees
WHERE
salary <=> 12000;
IS NULL 与 <=> 对比:
- IS NULL:专门用于判断 NULL 值,可读性高,建议优先使用
- <=>:既可以判断 NULL 值,又可以判断普通数值,但可读性较低
3. 排序查询(ORDER BY)
排序查询允许我们按照指定的列对结果集进行排序,这在数据展示和分析中非常有用。
3.1 排序查询基本语法
sql
-- 排序查询总结语法格式:
SELECT
查询列表 (3)
FROM
表名 (1)
[WHERE 筛选条件] (2)
ORDER BY 排序列表 [ASC | DESC] (4)
语法说明:
- ASC:代表升序(Ascending),从小到大排列
- DESC:代表降序(Descending),从大到小排列
- 如果不指定排序方向,默认使用 ASC(升序)
- ORDER BY 子句支持单个字段、多个字段、表达式、函数、别名
- ORDER BY 子句一般放在查询语句的最后面(LIMIT 子句除外)
3.2 基础排序示例
sql
-- 示例:查询员工信息,要求工资从高到低排序
/* 分析:
查询的表:employees
查询的字段:*
查询的条件:无
排序条件:salary DESC
*/
SELECT
*
FROM
employees
ORDER BY salary DESC;
-- 默认升序排序(ASC 可以省略)
SELECT
*
FROM
employees
ORDER BY salary;
3.3 带筛选条件的排序
sql
-- 示例:查询部门编号大于等于90的员工信息,按入职时间的先后顺序进行排序
/* 分析:
查询的表:employees
查询的字段:*
查询的条件:department_id >= 90
排序条件:hiredate ASC
*/
SELECT
*
FROM
employees
WHERE
department_id >= 90
ORDER BY
hiredate ASC;
3.4 按表达式排序
sql
-- 示例:按年薪的高低显示员工的信息和年薪
/* 分析:
查询的表:employees
查询的字段:*, 年薪
查询的条件:无
排序条件:salary * 12 * (1 + commission_pct) DESC
*/
-- IFNULL(commission_pct,0):判断是否为空,如果为空补0
SELECT
*,
salary * 12 * (1 + IFNULL(commission_pct,0)) AS 年薪
FROM
employees
ORDER BY
salary * 12 * (1 + IFNULL(commission_pct,0)) DESC;
3.5 按别名排序
sql
-- 示例:按年薪的高低显示员工的信息和年薪(按别名排序)
SELECT
*,
salary * 12 * (1 + IFNULL(commission_pct,0)) AS 年薪
FROM
employees
ORDER BY
年薪 DESC;
3.6 按函数排序
sql
-- 示例:按姓名的长度显示员工的姓名和工资
/* 分析:
查询的表:employees
查询的字段:姓名长度, 姓名, 工资
查询的条件:无
排序条件:函数排序 DESC
*/
SELECT
LENGTH(CONCAT(last_name, first_name)) AS 姓名长度,
CONCAT(last_name, first_name) AS 姓名,
salary
FROM
employees
ORDER BY
LENGTH(CONCAT(last_name, first_name)) DESC;
3.7 多字段排序
sql
-- 示例:查询员工信息,要求先按工资升序,再按员工编号降序
/* 分析:
查询的表:employees
查询的字段:*
查询的条件:无
排序条件:salary ASC, employee_id DESC
*/
SELECT
*
FROM
employees
ORDER BY
salary ASC, employee_id DESC;
4. MySQL 常见函数详解
函数是将一组逻辑语句封装在方法中,对外暴露方法名的工具。函数的好处在于隐藏了实现细节,提高了代码的重用性。
4.1 函数概述
函数调用语法格式 :SELECT 函数名(实参列表) [FROM 表名]
函数特点:
- 叫什么(函数名称)
- 干什么(函数功能)
函数分类:
- 单行函数:字符函数、数值函数、日期函数、其他函数、流程控制函数
- 分组函数(聚合函数):用于对一组值执行计算并返回单个值
4.2 字符函数
4.2.1 LENGTH(str) - 获取字节个数
sql
-- 获取参数值的字节个数
SELECT LENGTH('hello'); -- 返回 5
-- 注意:对于非 ASCII 字符(如汉字),LENGTH 函数返回的不是字符的个数,而是字符串的字节数
SELECT LENGTH('你好hello'); -- 在 UTF-8 编码下,每个汉字占3个字节,返回 11(3+3+5)
查看 MySQL 默认编码格式:
sql
SHOW VARIABLES LIKE '%char%';
4.2.2 CONCAT() - 字符串连接
sql
-- 返回连接后的字符串
SELECT CONCAT(last_name, first_name) FROM employees;
-- 连接常量字符串
SELECT CONCAT('2026', '-', '08', '-', '17');
4.2.3 CONCAT_WS() - 带分隔符的连接
sql
-- 返回带分隔符的连接结果
SELECT CONCAT_WS('-', '2026', '08', '17'); -- 返回 '2026-08-17'
4.2.4 UPPER() 和 LOWER() - 大小写转换
sql
-- UPPER(str):将字符串转换为大写
SELECT UPPER('hello'); -- 返回 'HELLO'
-- LOWER(str):将字符串转换为小写
SELECT LOWER('HELLO'); -- 返回 'hello'
-- 示例:将姓变为大写,名变为小写,然后拼接
SELECT
CONCAT(UPPER(last_name), LOWER(first_name)) AS name_concat
FROM
employees;
-- 使用 CONCAT_WS 添加分隔符
SELECT
CONCAT_WS('_', UPPER(last_name), LOWER(first_name)) AS name_concat
FROM
employees;
4.2.5 SUBSTR() / SUBSTRING() - 截取子字符串
sql
-- SUBSTR(str,pos):从指定位置开始截取到字符串末尾
SELECT SUBSTR('欢迎来到兰智数加学院', 5) AS out_put; -- 返回 '兰智数加学院'
-- SUBSTR(str,pos,len):从指定位置开始截取指定长度的子字符串
SELECT SUBSTR('欢迎来到兰智数加学院', 7, 2) AS out_put; -- 返回 '数加'
SELECT SUBSTRING('欢迎来到兰智数加学院', 7, 2) AS out_put; -- 返回 '数加'
参数说明:
str:原始字符串pos:子字符串的起始位置,从 1 开始计数len:要截取的长度(可选)
sql
-- 示例:姓名中的姓首字母大写,其他字符小写,然后使用_拼接
SELECT
CONCAT(UPPER(SUBSTR(last_name, 1, 1)), '_', LOWER(SUBSTR(last_name, 2))) AS out_put
FROM
employees;
4.2.6 INSTR() - 查找子字符串位置
sql
-- 返回子字符串首次出现的索引位置
SELECT INSTR('欢迎来到兰智数加学院', '学院'); -- 返回子字符串的位置
-- 如果子字符串不在原始字符串中,则返回 0
SELECT INSTR('欢迎来到兰智数加学院', '数模'); -- 返回 0
-- 注意:参数是二进制字符串时才区分大小写
SELECT INSTR('欢hhhh迎来到HHHH兰智数加学院', 'H'); -- 返回位置
4.2.7 TRIM() 系列函数 - 去除空格
sql
-- TRIM():删除前导空格和尾随空格
SELECT LENGTH(TRIM(' 兰智数加学院 ')) AS out_put; -- 返回去除空格后的长度
SELECT TRIM(' 兰智数加学院 ') AS out_put; -- 返回 '兰智数加学院'
-- RTRIM():删除尾随空格(右侧空格)
-- LTRIM():删除前导空格(左侧空格)
思考题:如何删除字符串中间的空格?例如 "兰智 数加 学院" 中间的空格。
4.2.8 LPAD() 和 RPAD() - 字符串填充
sql
-- LPAD(str,len,padstr):在字符串左侧填充指定字符,使总长度达到指定值
SELECT LPAD('数加', 4, '*') AS output; -- 返回 '**数加'
-- RPAD(str,len,padstr):在字符串右侧填充指定字符
SELECT RPAD('数加', 4, '*') AS output; -- 返回 '数加**'
思考题:如何将 "马冬梅" 转换为 "马*梅"?
4.2.9 REPLACE() - 字符串替换
sql
-- REPLACE(str,from_str,to_str):替换指定字符串的所有出现位置
SELECT REPLACE('欢迎来到兰智数加学院', '学院', '大学') AS out_put; -- 返回 '欢迎来到兰智数加大学'
4.3 数学函数
4.3.1 ROUND() - 四舍五入
sql
-- ROUND(X):将参数四舍五入到整数
SELECT ROUND(3.14); -- 返回 3
-- ROUND(X,D):将参数四舍五入到 D 位小数
SELECT ROUND(3.1415926, 2) AS out_put; -- 返回 3.14
5. 实战应用与最佳实践
5.1 综合查询示例
结合条件查询、排序和函数使用,我们可以构建更复杂的查询:
sql
-- 示例:查询部门编号在 50-100 之间,按姓名长度降序排列,并显示格式化后的姓名
SELECT
employee_id,
CONCAT(UPPER(SUBSTR(last_name, 1, 1)), LOWER(SUBSTR(last_name, 2)),
' ',
UPPER(SUBSTR(first_name, 1, 1)), LOWER(SUBSTR(first_name, 2))) AS formatted_name,
salary,
department_id,
LENGTH(CONCAT(last_name, first_name)) AS name_length
FROM
employees
WHERE
department_id BETWEEN 50 AND 100
AND commission_pct IS NOT NULL
ORDER BY
name_length DESC,
salary ASC;
5.2 性能优化建议
- 合理使用索引:在 WHERE 和 ORDER BY 子句中频繁使用的列上创建索引
- 避免在 WHERE 子句中对列进行函数操作:这会导致索引失效
- 使用 EXPLAIN 分析查询计划:了解 MySQL 如何执行查询
- 限制结果集大小:使用 LIMIT 子句避免返回过多数据
5.3 常见错误与解决方法
- NULL 值处理错误:始终使用 IS NULL 或 IS NOT NULL 判断 NULL 值
- 字符串函数编码问题:注意字符集对 LENGTH() 等函数的影响
- 排序性能问题:对大表排序时考虑添加合适的索引
- 函数嵌套过深:避免过度嵌套函数,影响可读性和性能
6. 总结
本文详细介绍了 MySQL 中条件查询、排序查询以及常用函数的使用方法,涵盖了从基础语法到实战应用的完整知识体系。
核心要点回顾:
- 条件查询(WHERE):掌握 IN 运算符简化多值匹配,理解 NULL 值的特殊性并使用 IS NULL/IS NOT NULL 进行判断,了解安全等于运算符(<=>)的用法。
- 排序查询(ORDER BY):支持按字段、表达式、函数、别名以及多字段组合排序,ASC(升序)和 DESC(降序)控制排序方向。
- 常用函数:包括字符函数(LENGTH、CONCAT、SUBSTR、INSTR、TRIM、LPAD/RPAD、REPLACE 等)和数学函数(ROUND 等),这些函数能显著提升数据处理能力。
- 实战应用:通过综合查询示例展示了如何将条件、排序和函数结合使用,构建复杂且高效的查询语句。
- 最佳实践:合理使用索引、避免 WHERE 子句中的函数操作、使用 EXPLAIN 分析查询计划等优化技巧,以及常见错误的解决方法。
SQL 查询是数据库操作的核心技能,熟练掌握条件查询、排序和函数的使用,能够帮助开发者更高效地从数据库中提取、分析和展示所需数据。建议读者在实际项目中多加练习,结合具体业务场景灵活运用这些技巧,不断提升 SQL 查询能力。