源本科技 | 码上会

MySQL DQL 数据查询语言

2026/03/14
42
0

什么是 DQL

DQL(Data Query Language,数据查询语言)是 SQL 中最核心、使用频率最高的部分。它的唯一使命就是从数据库中检索数据。虽然 SQL 标准中将其归类为 DML 的一部分,但在实际工程和教学中,由于 SELECT 语句的复杂性和重要性,通常将其独立称为 DQL。

核心价值

  • 数据洞察:将存储在磁盘上的原始数据转化为有价值的信息。

  • 灵活筛选:通过条件过滤、排序、分组和聚合,精准获取所需数据子集。

  • 应用基石:几乎所有后端 API、报表系统、数据分析工具都依赖 DQL 获取数据。


基础查询

列查询

  • 指定列查询(推荐):只获取需要的字段,减少网络传输和内存消耗。

    SELECT first_name, last_name FROM employees;
  • 全列查询(慎用):使用 * 获取所有列。仅在调试或确实需要所有字段时使用。

    SELECT * FROM employees; 
    -- 缺点:如果表结构变化,代码可能失效;传输不必要的大字段(如 TEXT/BLOB)会降低性能。

去除重复记录

当只需要了解某列有哪些不同的值时,使用 DISTINCT 去重。

-- 查询公司有哪些不同的部门
SELECT DISTINCT department FROM employees;

-- 多列去重:只有当所有指定列的组合都相同时,才视为重复
SELECT DISTINCT department, job_title FROM employees;

使用别名

给列或表起别名,可以提高结果的可读性,或在后续计算中简化引用。

-- 列别名:让输出标题更友好
SELECT 
    product_name AS item_name, 
    price AS unit_price, 
    price * 0.9 AS discounted_price 
FROM products;

-- 表别名:在多表连接时非常有用(见高级篇)
SELECT e.first_name, d.dept_name 
FROM employees AS e, departments AS d 
WHERE e.dept_id = d.id;

注意AS 关键字在列别名中通常可以省略,直接写空格即可,但在表别名中建议保留以增强可读性。


条件查询

WHERE 子句用于过滤记录,只返回满足条件的行。它是数据筛选的第一道关卡。

比较运算符

运算符

描述

示例

=

等于

WHERE age = 18

<>!=

不等于

WHERE status != 'deleted'

>, <, >=, <=

大于 / 小于 / 大于等于 / 小于等于

WHERE salary > 5000

BETWEEN ... AND ...

在某个范围内(包含边界)

WHERE age BETWEEN 18 AND 60

IN (...)

在指定集合中

WHERE dept_id IN (1, 3, 5)

IS NULL / IS NOT NULL

判断空值

WHERE email IS NOT NULL

重要提示:判断 NULL 值必须使用 IS NULLIS NOT NULL,不能使用 = NULL!= NULL,因为 NULL 在 SQL 中表示“未知”,与任何值比较(包括它自己)结果都是 UNKNOWN。

逻辑运算符

用于组合多个条件:

  • AND:所有条件都必须满足。

  • OR:只要有一个条件满足即可。

  • NOT:取反。

-- 案例:查询部门 ID 为 1 且 工资大于 5000 的员工
SELECT * FROM employees 
WHERE department_id = 1 AND salary > 5000;

-- 案例:查询状态为 'Shipped' 或 'Delivered' 且 金额大于 1000 的订单
SELECT * FROM orders 
WHERE (status = 'Shipped' OR status = 'Delivered') AND total_amount > 1000;

模糊查询

用于字符串匹配,支持通配符:

  • %:匹配任意长度(包括 0 个)的字符。

  • _:匹配单个字符。

-- 以 'App' 开头的产品 (如 Apple, Application)
SELECT * FROM products WHERE product_name LIKE 'App%';

-- 包含 'phone' 的产品 (如 iPhone, Smartphone)
SELECT * FROM products WHERE product_name LIKE '%phone%';

-- 第二个字母是 'a' 的名字 (如 David, James)
SELECT * FROM users WHERE username LIKE '_a%';

性能警告LIKE '%keyword%'(前缀通配)会导致索引失效,进行全表扫描。在大数据量下需谨慎使用,或考虑使用全文索引。


排序查询

默认情况下,数据库返回数据的顺序是不确定的(通常取决于存储引擎和插入顺序)。使用 ORDER BY 可以明确指定排序规则。

单列排序

-- 按价格升序排列(ASC 可省略,默认为升序)
SELECT product_name, price FROM products ORDER BY price ASC;

-- 按注册日期降序排列(最新的在前)
SELECT * FROM users ORDER BY registration_date DESC;

多列排序

当第一列的值相同时,按第二列排序,依此类推。

-- 先按订单日期升序,同一天内的订单按金额降序排列
SELECT customer_name, order_date, total_amount 
FROM orders 
ORDER BY order_date ASC, total_amount DESC;

实战演练

基于之前创建的 users 表,我们插入模拟数据并进行多维度查询。

数据准备

INSERT INTO users (username, password, email, registration_date) VALUES
    ('user1', 'pass123', 'user1@example.com', '2022-11-15 10:00:00'),
    ('user2', 'pass456', 'user2@example.com', '2023-02-20 14:30:00'),
    ('user3', 'pass789', 'user3@example.com', '2023-01-05 09:15:00'),
    ('alice', 'secure_pwd', 'alice@example.com', '2023-03-10 11:20:00'),
    ('bob', 'bob_pwd', 'bob@example.com', '2022-12-25 16:45:00'),
    ('charlie', 'charlie_pwd', 'charlie@example.com', '2023-01-20 08:00:00'),
    ('david', 'david_pwd', 'david@example.com', '2023-02-14 12:00:00'),
    ('eve', 'eve_pwd', 'eve@example.com', '2022-10-01 07:30:00');
-- 注:实际插入时 NOW() 会生成当前时间,这里为了演示排序效果,硬编码了不同日期

任务一:基础查询

需求:检索所有用户的用户名和注册日期。

SELECT username, registration_date 
FROM users;

任务二:条件查询

需求:检索所有注册日期在 2023-01-01 之后的用户信息。

SELECT * 
FROM users 
WHERE registration_date > '2023-01-01 00:00:00';

解析:日期时间比较可以直接使用字符串格式,MySQL 会自动转换。

任务三:组合查询与排序

需求

  1. 找出用户名中包含 "er" 的用户。

  2. 按注册日期降序排列(最新的在前)。

  3. 如果日期相同,按用户名升序排列。

SELECT username, email, registration_date 
FROM users 
WHERE username LIKE '%er%' 
ORDER BY registration_date DESC, username ASC;

预期结果:user1, user2, user3, user4... 等包含 'er' 的用户会被选出,并按时间倒序展示。

任务四:去重统计

需求:查看系统中有哪些不同的密码被使用过(仅用于演示 DISTINCT,实际生产严禁明文存密码)。

SELECT DISTINCT password 
FROM users;

最佳实践

DQL 是开发者最强大的武器,掌握以下原则能让你的查询更高效、更安全:

  1. 最小化原则

    • SELECT 需要的列,避免 SELECT *

    • WHERE 必要的条件,尽早过滤数据。

  2. 索引意识

    • WHERE, ORDER BY, JOIN 的关联列上建立索引,可以极大提升查询速度。

    • 避免在索引列上进行函数运算(如 WHERE YEAR(date_col) = 2023 会导致索引失效,应改为 WHERE date_col >= '2023-01-01' AND date_col < '2024-01-01')。

  3. NULL 处理

    • 永远记住 NULL != NULL,使用 IS NULL 进行判断。

  4. 可读性

    • 使用有意义的别名。

    • 格式化 SQL 代码(关键字大写,子句换行),便于团队协作和维护。