SQL DQL 详解:SELECT 查询与核心子句
DQL(Data Query Language)是 SQL 中最常用的部分,核心是 SELECT
语句,用于从数据库检索数据。以下是完整结构和各子句的详细解析:
SELECT [DISTINCT] column_list -- 选择字段
FROM table_sources -- 数据来源
[JOIN_TYPE JOIN table ON join_condition] -- 多表连接
[WHERE search_condition] -- 行级过滤
[GROUP BY grouping_columns] -- 数据分组
[HAVING group_condition] -- 分组过滤
[ORDER BY sort_columns [ASC|DESC]] -- 结果排序
[LIMIT [offset,] row_count]; -- 行数限制
一、SELECT(字段列表)
功能:指定要检索的列或表达式
SELECT
first_name,
last_name,
salary * 1.1 AS new_salary -- 使用表达式和别名
FROM employees;
关键点:
*
选择所有列(生产环境慎用)- 使用
AS
赋予列别名(salary AS 月薪
) DISTINCT
去重:SELECT DISTINCT department_id
- 支持表达式:
quantity * unit_price AS total
二、FROM(数据来源)
功能:指定查询的源表
FROM employees
FROM orders INNER JOIN customers -- 多表查询
三、WHERE(行级过滤)
功能:基于条件筛选行
WHERE salary > 5000
AND department_id = 10
AND hire_date >= '2023-01-01'
常用运算符:
运算符 | 示例 | 说明 |
---|---|---|
= | id = 101 | 等于 |
=> <= | salary > 5000 | 大小比较 |
BETWEEN ... AND ... | age BETWEEN 20 AND 30 | 范围查询 |
LIKE | name LIKE 'J%' | 模式匹配(% 任意字符,_ 单个字符) |
IN(...) | id IN (101, 102, 103) | 值列表匹配 |
IS NULL | manager_id IS NULL | 空值检查 |
AND/OR/NOT | A AND B | 逻辑组合 |
四、JOIN(多表连接)
功能:组合多个表的数据
1. INNER JOIN(内连接)
SELECT employees.name, departments.dept_name
FROM employees
INNER JOIN departments
ON employees.dept_id = departments.id
- 仅返回匹配的行(交集)
2. LEFT JOIN(左外连接)
SELECT customers.name, orders.amount
FROM customers
LEFT JOIN orders
ON customers.id = orders.customer_id
- 返回左表所有行 + 右表匹配行(无匹配显示NULL)
3. 其他连接类型:
RIGHT JOIN
:保留右表所有行FULL OUTER JOIN
:返回所有行(MySQL 需用UNION
模拟)CROSS JOIN
:笛卡尔积(慎用)
五、GROUP BY(数据分组)
功能:将数据按列分组,用于聚合计算
SELECT
department_id,
COUNT(*) AS employee_count, -- 聚合函数
AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
常用聚合函数:
COUNT()
:计数SUM()
:求和AVG()
:平均值MAX()
/MIN()
:最大/最小值
重要规则:
- SELECT 中的非聚合列必须出现在 GROUP BY 中
- 可以按多列分组:
GROUP BY year, month
六、HAVING(分组过滤)
功能:对 GROUP BY 的分组结果进行过滤
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 8000 -- 过滤分组
与 WHERE 的区别:
特性 | WHERE | HAVING |
---|---|---|
执行时机 | 分组前 | 分组后 |
可用的列 | 原始列 | 分组列/聚合结果 |
聚合函数 | ❌ 不可用 | ✅ 可用 |
七、ORDER BY(结果排序)
功能:对结果集排序
SELECT name, salary
FROM employees
ORDER BY
salary DESC, -- 先按工资降序
hire_date ASC -- 再按入职日期升序
排序规则:
ASC
:升序(默认)DESC
:降序- 可排序表达式:
ORDER BY LENGTH(name)
- NULL 值处理:
ORDER BY salary DESC NULLS LAST
八、LIMIT(行数限制)
功能:限制返回的行数(常用于分页)
SELECT 字段列表
FROM 表名
LIMIT 起始索引, 查询记录数; -- 返回前10行
分页实现:
LIMIT 10 OFFSET 20 -- 跳过前20行,取10行(第21-30行)
-- MySQL简写:LIMIT 20, 10
注意
- 起始索引从0开始,起始索引 = (查询页码-1) * 每页显示记录数。
- 分页查询是数据库的方言,不同数据库有不同实现,MySQL中为LIMIT。
- 如果查询的是第一页数据,起始索引可以省略,直接简写为limit10。
完整工作流程与执行顺序
- FROM:确定数据来源(表)
- JOIN:连接关联表
- WHERE:过滤符合条件的行
- GROUP BY:对数据进行分组
- HAVING:过滤分组结果
- SELECT:选择要返回的列
- ORDER BY:对结果排序
- LIMIT:限制返回行数
-- 完整示例:查询2023年销售额超10万的部门
SELECT
d.department_name,
SUM(s.amount) AS total_sales
FROM sales s
INNER JOIN employees e ON s.employee_id = e.id
INNER JOIN departments d ON e.department_id = d.id
WHERE s.sale_date BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY d.department_id
HAVING total_sales > 100000
ORDER BY total_sales DESC
LIMIT 5;
关键要点:
- WHERE 在 GROUP BY 前执行,不能使用聚合函数
- HAVING 可使用聚合函数,但效率低于 WHERE 提前过滤
- ORDER BY 可使用 SELECT 中定义的别名
- LIMIT 应始终与 ORDER BY 配合使用(确保顺序确定)
- 多表 JOIN 时使用表别名提高可读性