SQL语言中的SELECT语句详解
SELECT语句是SQL语言中最核心、最常用的数据查询命令,用于从数据库表中检索数据。无论是简单的单表查询,还是复杂的多表联合查询,SELECT都是每个数据库开发者必须掌握的基础技能。本文将系统介绍SELECT语句的完整语法、各种子句的使用方法,并通过大量示例帮助读者快速上手。
一、SELECT语句的基本语法
SELECT语句的最基本形式如下:
SELECT 列名1, 列名2, ... FROM 表名 [WHERE 条件] [GROUP BY 列名] [HAVING 分组条件] [ORDER BY 列名 [ASC|DESC]] [LIMIT 数量];
其中,SELECT和FROM是必须的子句,其他都是可选的。下面逐部分进行说明。
二、选择列与表达式
2.1 选择所有列
使用星号(*)可以查询表中所有列:
SELECT * FROM employees;
2.2 选择指定列
列出需要查询的列名,用逗号分隔:
SELECT name, age, department FROM employees;
2.3 使用别名
可以使用AS关键字为列或表达式设置别名,使结果更易读:
SELECT name AS 员工姓名, salary * 12 AS 年薪 FROM employees;
2.4 使用表达式与函数
SELECT语句中可以使用算术运算符、字符串函数、日期函数等:
SELECT UPPER(name) AS 大写姓名, salary + bonus AS 总收入, DATEDIFF(NOW(), hire_date) AS 在职天数 FROM employees;
三、WHERE子句:条件过滤
WHERE子句用于筛选出满足特定条件的行。支持多种运算符和条件组合。
3.1 比较运算符
-- 等于 SELECT * FROM employees WHERE age = 25; -- 不等于 SELECT * FROM employees WHERE age != 30; -- 大于、小于 SELECT * FROM products WHERE price > 100; -- 范围(BETWEEN) SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
3.2 逻辑运算符
-- AND(且) SELECT * FROM employees WHERE department = 'Sales' AND salary > 50000; -- OR(或) SELECT * FROM employees WHERE department = 'IT' OR department = 'HR'; -- NOT(非) SELECT * FROM products WHERE NOT category = 'Electronics';
3.3 IN与NOT IN
SELECT * FROM employees WHERE department IN ('Sales', 'IT', 'HR');
SELECT * FROM products WHERE id NOT IN (1001, 1002, 1003);3.4 LIKE模糊匹配
使用%表示任意多个字符,_表示单个字符:
-- 以'张'开头的名字 SELECT * FROM employees WHERE name LIKE '张%'; -- 名字包含'伟'的员工 SELECT * FROM employees WHERE name LIKE '%伟%'; -- 名字第二个字是'小'(下划线 _) SELECT * FROM employees WHERE name LIKE '_小%';
3.5 IS NULL与IS NOT NULL
SELECT * FROM employees WHERE email IS NULL; SELECT * FROM products WHERE description IS NOT NULL;
四、ORDER BY子句:排序
使用ORDER BY对查询结果进行排序,默认为升序(ASC),降序用DESC:
-- 按工资升序 SELECT name, salary FROM employees ORDER BY salary; -- 按工资降序,如果相同则按年龄升序 SELECT name, age, salary FROM employees ORDER BY salary DESC, age ASC;
五、LIMIT子句:限制结果行数
用于限制返回的记录数量,常用于分页:
-- 返回前10条记录 SELECT * FROM employees LIMIT 10; -- 跳过前5条,返回接下来的10条(第6到第15条) SELECT * FROM employees LIMIT 10 OFFSET 5; -- 另一种写法(MySQL、PostgreSQL等支持) SELECT * FROM employees LIMIT 5, 10; -- 跳过5条,取10条
六、GROUP BY子句:分组聚合
GROUP BY将查询结果按一个或多个列分组,常与聚合函数配合使用。
6.1 基本分组
-- 按部门统计人数 SELECT department, COUNT(*) AS 人数 FROM employees GROUP BY department;
6.2 常用聚合函数
| 函数 | 说明 | 示例 |
|---|---|---|
| COUNT() | 统计行数 | COUNT(*) 或 COUNT(列名) |
| SUM() | 求和 | SUM(salary) |
| AVG() | 平均值 | AVG(price) |
| MAX() | 最大值 | MAX(age) |
| MIN() | 最小值 | MIN(salary) |
6.3 多列分组
-- 按部门和职位分组 SELECT department, job_title, COUNT(*) AS 人数, AVG(salary) AS 平均薪资 FROM employees GROUP BY department, job_title;
七、HAVING子句:对分组结果过滤
HAVING与WHERE类似,但WHERE是对原始行进行过滤,而HAVING是对分组后的结果进行过滤:
-- 找出平均工资大于60000的部门 SELECT department, AVG(salary) AS 平均薪资 FROM employees GROUP BY department HAVING AVG(salary) > 60000; -- 注意:WHERE不能使用聚合函数,但HAVING可以 -- 错误示例: -- SELECT department, AVG(salary) FROM employees WHERE AVG(salary) > 60000 GROUP BY department;
八、DISTINCT关键字:去重
使用DISTINCT可以去除结果中重复的行:
-- 查询所有不同的部门名称 SELECT DISTINCT department FROM employees; -- 多列去重:只有当所有指定列都相同时才视为重复 SELECT DISTINCT department, city FROM employees;
九、多表连接查询
实际开发中经常需要从多张关联表中查询数据,连接查询是最常用的方式。
9.1 INNER JOIN(内连接)
-- 查询员工及其部门名称 SELECT e.name, e.department_id, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.department_id;
9.2 LEFT JOIN(左外连接)
-- 左表(employees)的所有记录都会被保留,即使右表没有匹配 SELECT e.name, o.order_id, o.order_date FROM employees e LEFT JOIN orders o ON e.employee_id = o.employee_id;
9.3 RIGHT JOIN(右外连接)
-- 右表(orders)的所有记录都会被保留 SELECT e.name, o.order_id FROM employees e RIGHT JOIN orders o ON e.employee_id = o.employee_id;
9.4 自连接
-- 查询员工及其经理的姓名(同一张表连接) SELECT e.name AS 员工姓名, m.name AS 经理姓名 FROM employees e LEFT JOIN employees m ON e.manager_id = m.employee_id;
十、子查询
子查询可以嵌套在SELECT、FROM、WHERE、HAVING等子句中。
10.1 WHERE子句中的子查询
-- 找出工资高于平均工资的员工 SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
10.2 FROM子句中的子查询(派生表)
-- 先查询每个部门的平均工资,再找出大于整体平均的部门 SELECT department, avg_salary FROM ( SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department ) AS dept_avg WHERE avg_salary > 50000;
10.3 关联子查询
-- 找出每个部门中工资高于该部门平均工资的员工 SELECT name, department, salary FROM employees e WHERE salary > ( SELECT AVG(salary) FROM employees WHERE department = e.department );
十一、使用UNION合并结果集
UNION用于合并两个或多个SELECT语句的结果,默认去重:
-- 合并销售部和IT部的员工 SELECT name, department FROM employees WHERE department = 'Sales' UNION SELECT name, department FROM employees WHERE department = 'IT'; -- 如果需要保留重复行,使用 UNION ALL SELECT name FROM customers UNION ALL SELECT name FROM suppliers;
十二、完整的SELECT语句执行顺序
理解SELECT语句各子句的执行顺序,有助于写出正确的查询:
(1) FROM 子句 -- 确定数据来源 (2) WHERE 子句 -- 过滤原始行 (3) GROUP BY 子句 -- 对过滤后的数据分组 (4) HAVING 子句 -- 过滤分组后的结果 (5) SELECT 子句 -- 选择列或计算表达式 (6) ORDER BY 子句 -- 对最终结果排序 (7) LIMIT 子句 -- 限制返回的行数
十三、实践建议与常见错误
13.1 常见错误
WHERE中使用聚合函数:聚合函数只能出现在SELECT、HAVING或ORDER BY中。
SELECT列表中包含未分组的列:当使用GROUP BY时,SELECT中的非聚合列必须出现在GROUP BY中(除非数据库配置允许)。
HAVING与WHERE混淆:HAVING只能与GROUP BY配合过滤分组,WHERE在分组之前过滤行。
LIKE模式中的通配符误用
13.2 性能优化提示
尽量使用索引列作为WHERE条件,避免全表扫描。
避免在WHERE中使用函数包装列名(例如
WHERE YEAR(date) = 2024可能无法使用索引)。对于大量数据的分页查询,使用
LIMIT配合索引推荐的方法,避免使用OFFSET在数据量大的情况下。子查询性能可能较差,可以考虑使用JOIN替代。
13.3 调试技巧
如果查询结果不如预期,可以逐步测试:
-- 1. 先测试基础数据 SELECT * FROM employees LIMIT 5; -- 2. 确认WHERE条件是否匹配 SELECT COUNT(*) FROM employees WHERE department = 'Sales'; -- 3. 检查分组效果 SELECT department, COUNT(*) FROM employees GROUP BY department; -- 4. 逐步添加ORDER BY和LIMIT -- 这样能快速定位问题所在
总结
SELECT语句是SQL最核心的功能之一,掌握它的各种子句和用法,是进行数据库开发的基础。本文从基本语法出发,逐步介绍了列选择、条件过滤、排序、分组、连接查询、子查询等核心知识点,并提供了实用的示例和注意事项。希望读者能通过本文的学习,灵活运用SELECT语句解决实际开发中的数据查询需求。