查询详解

最后更新: 2026-01-22 作者: MySQL Team
页面目录

第四章:查询详解


4.1 基本查询

SELECT 语法

-- 查询所有字段
SELECT * FROM users;

-- 查询指定字段
SELECT id, username, email FROM users;

-- 带别名
SELECT 
    id AS user_id,
    username AS name,
    email AS "Email Address"
FROM users;

-- 字段计算
SELECT 
    product_name,
    price,
    quantity,
    price * quantity AS total
FROM orders;

DISTINCT 去重

-- 去除重复记录
SELECT DISTINCT department FROM employees;

-- 多字段组合去重
SELECT DISTINCT department, position FROM employees;

LIMIT 限制结果

-- 限制返回行数
SELECT * FROM users LIMIT 10;

-- 分页查询(第11-20条)
SELECT * FROM users LIMIT 10 OFFSET 10;
-- 或
SELECT * FROM users LIMIT 10, 10;

-- 查询前10条
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;

4.2 WHERE 条件查询

比较条件

-- 基本比较
SELECT * FROM users WHERE age >= 18;
SELECT * FROM products WHERE price < 100;
SELECT * FROM orders WHERE status != 'cancelled';

-- 字符串比较
SELECT * FROM users WHERE name = '张三';
SELECT * FROM users WHERE name != '张三';

范围条件

-- BETWEEN AND(包含边界)
SELECT * FROM products WHERE price BETWEEN 100 AND 500;

-- IN(多值匹配)
SELECT * FROM users WHERE city IN ('北京', '上海', '广州', '深圳');

-- NOT IN
SELECT * FROM users WHERE city NOT IN ('北京', '上海');

NULL 值查询

-- 查询为空
SELECT * FROM users WHERE phone IS NULL;

-- 查询不为空
SELECT * FROM users WHERE phone IS NOT NULL;

模糊查询

-- LIKE 模式匹配
-- % 匹配任意字符
SELECT * FROM users WHERE name LIKE '张%';      -- 张三, 张三丰
SELECT * FROM users WHERE email LIKE '%@gmail.com';
SELECT * FROM users WHERE name LIKE '%三%';     -- 包含"三"

-- _ 匹配单个字符
SELECT * FROM users WHERE name LIKE '张_';      -- 张三, 张四
SELECT * FROM users WHERE name LIKE '张__';     -- 张三丰

-- NOT LIKE
SELECT * FROM users WHERE name NOT LIKE '%admin%';

-- REGEXP/RLIKE(正则表达式)
SELECT * FROM users WHERE name REGEXP '^张';
SELECT * FROM users WHERE email REGEXP '^[a-z]+@gmail\\.com$';

组合条件

-- AND 逻辑与
SELECT * FROM users WHERE age >= 18 AND status = 'active';

-- OR 逻辑或
SELECT * FROM users WHERE city = '北京' OR city = '上海';

-- NOT 逻辑非
SELECT * FROM users WHERE NOT status = 'banned';

-- 优先级:NOT > AND > OR
SELECT * FROM users 
WHERE (age >= 18 AND status = 'active') 
   OR (age < 18 AND parent_consent = 'Y');

4.3 ORDER BY 排序

单字段排序

-- 升序(ASC,默认)
SELECT * FROM products ORDER BY price ASC;

-- 降序(DESC)
SELECT * FROM products ORDER BY price DESC;

-- 按别名排序
SELECT 
    name,
    price,
    price * 1.1 AS sale_price
FROM products ORDER BY sale_price;

多字段排序

-- 先按第一个字段,相同值时按第二个字段
SELECT * FROM employees ORDER BY department ASC, salary DESC;

-- 不同字段不同方向
SELECT * FROM users ORDER BY status ASC, created_at DESC;

表达式排序

-- 按计算结果排序
SELECT 
    product_name,
    price,
    quantity,
    price * quantity AS total
FROM orders 
ORDER BY total DESC;

-- 随机排序
SELECT * FROM users ORDER BY RAND();

4.4 聚合与分组

GROUP BY 分组

-- 按部门统计人数
SELECT department, COUNT(*) AS emp_count
FROM employees
GROUP BY department;

-- 按状态统计订单
SELECT status, COUNT(*) AS order_count, SUM(total) AS total_amount
FROM orders
GROUP BY status;

-- 多字段分组
SELECT department, position, COUNT(*) AS headcount
FROM employees
GROUP BY department, position;

HAVING 过滤分组

-- HAVING 过滤分组后的结果
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 10000;

-- WHERE vs HAVING
-- WHERE: 过滤行(在分组前过滤)
-- HAVING: 过滤分组(在分组后过滤)

-- 示例:统计每个部门的平均工资,筛选人数大于5的部门
SELECT department, COUNT(*) AS cnt, AVG(salary) AS avg_sal
FROM employees
WHERE status = 'active'        -- 先过滤行
GROUP BY department
HAVING COUNT(*) > 5            -- 再过滤分组
ORDER BY avg_sal DESC;         -- 最后排序

GROUP_CONCAT 分组合并

-- 合并分组内的值
SELECT department, GROUP_CONCAT(name ORDER BY salary DESC SEPARATOR ', ') AS members
FROM employees
GROUP BY department;

-- 去重合并
SELECT department, GROUP_CONCAT(DISTINCT position ORDER BY position) AS positions
FROM employees
GROUP BY department;

4.5 多表查询

交叉连接(CROSS JOIN)

-- 笛卡尔积(慎用)
SELECT * FROM table1 CROSS JOIN table2;
SELECT * FROM table1, table2;  -- 隐式写法

内连接(INNER JOIN)

-- 基本语法
SELECT o.id, o.order_no, u.username, u.email
FROM orders o
INNER JOIN users u ON o.user_id = u.id;

-- 隐式内连接
SELECT o.id, o.order_no, u.username
FROM orders o, users u
WHERE o.user_id = u.id;

-- 多表连接
SELECT o.id, o.order_no, u.username, p.product_name, oi.quantity
FROM orders o
INNER JOIN users u ON o.user_id = u.id
INNER JOIN order_items oi ON o.id = oi.order_id
INNER JOIN products p ON oi.product_id = p.id;

左外连接(LEFT JOIN)

-- 返回左表所有记录,右表无匹配则显示 NULL
SELECT u.id, u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;

-- 查询未下单用户
SELECT u.*
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;

右外连接(RIGHT JOIN)

-- 返回右表所有记录,左表无匹配则显示 NULL
SELECT u.username, o.order_no
FROM orders o
RIGHT JOIN users u ON o.user_id = u.id;

自连接

-- 查询每个员工的经理
SELECT 
    e.name AS employee,
    m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

-- 查询同部门的其他员工
SELECT e1.name, e2.name AS colleague
FROM employees e1
JOIN employees e2 ON e1.department = e2.department AND e1.id != e2.id;

USING 简化连接

-- 当连接字段名称相同时
SELECT * FROM orders
INNER JOIN order_items USING (order_id);

-- 等价于
SELECT * FROM orders
INNER JOIN order_items ON orders.order_id = order_items.order_id;

4.6 子查询

标量子查询

-- 返回单个值
SELECT * FROM products
WHERE price > (SELECT AVG(price) FROM products);

-- 查询最高工资员工
SELECT * FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);

列子查询

-- 返回一列值
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE status = 'completed');

-- NOT IN 排除
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM orders WHERE status = 'completed');

行子查询

-- 返回一行
SELECT * FROM employees
WHERE (department, salary) = (
    SELECT department, MAX(salary)
    FROM employees
    GROUP BY department
);

表子查询

-- 返回临时表
SELECT *
FROM (SELECT department, AVG(salary) AS avg_sal
      FROM employees
      GROUP BY department) AS dept_stats
WHERE avg_sal > 8000;

EXISTS Exists

-- EXISTS:检查子查询是否返回行
SELECT * FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 'completed'
);

-- NOT EXISTS
SELECT * FROM users u
WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

相关子查询

-- 子查询引用外层表
SELECT p1.product_name, p1.price
FROM products p1
WHERE p1.price > (
    SELECT AVG(p2.price) 
    FROM products p2 
    WHERE p2.category = p1.category
);

4.7 联合查询

UNION 合并

-- 合并多个 SELECT 结果(自动去重)
SELECT name FROM students
UNION
SELECT name FROM teachers;

-- UNION ALL(不去重,效率更高)
SELECT name FROM students
UNION ALL
SELECT name FROM teachers;

-- 带条件的 UNION
(SELECT id, name, '学生' AS type FROM students WHERE age >= 18)
UNION
(SELECT id, name, '教师' AS type FROM teachers WHERE status = 'active')
ORDER BY name;

4.8 高级查询技巧

CASE 表达式

SELECT 
    name,
    score,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END AS grade,
    CASE
        WHEN score >= 90 THEN '优秀'
        WHEN score >= 80 THEN '良好'
        WHEN score >= 60 THEN '及格'
        ELSE '不及格'
    END AS description
FROM students;

条件统计

-- 统计各状态数量
SELECT 
    SUM(status = 'pending') AS pending_count,
    SUM(status = 'processing') AS processing_count,
    SUM(status = 'completed') AS completed_count,
    COUNT(*) AS total
FROM orders;

-- 或使用 COUNT + CASE
SELECT 
    COUNT(CASE WHEN status = 'pending' THEN 1 END) AS pending_count,
    COUNT(CASE WHEN status = 'completed' THEN 1 END) AS completed_count
FROM orders;

排名查询

-- ROW_NUMBER():连续排名(无并列)
SELECT 
    name,
    score,
    ROW_NUMBER() OVER (ORDER BY score DESC) AS ranking
FROM students;

-- RANK():跳跃排名(有并列)
SELECT 
    name,
    score,
    RANK() OVER (ORDER BY score DESC) AS ranking
FROM students;

-- DENSE_RANK():密集排名(有并列)
SELECT 
    name,
    score,
    DENSE_RANK() OVER (ORDER BY score DESC) AS ranking
FROM students;

-- 分组排名
SELECT 
    department,
    name,
    salary,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;

累计计算

-- 累计求和
SELECT 
    order_date,
    amount,
    SUM(amount) OVER (ORDER BY order_date) AS cumulative_sum
FROM orders;

-- 分组累计
SELECT 
    department,
    order_date,
    amount,
    SUM(amount) OVER (PARTITION BY department ORDER BY order_date) AS dept_cumulative
FROM orders;

4.9 EXPLAIN 分析查询

-- 分析 SELECT 语句
EXPLAIN SELECT * FROM users WHERE id = 1;

-- 详细分析
EXPLAIN ANALYZE SELECT * FROM users WHERE email LIKE '%@example.com';

-- 查看所有字段
EXPLAIN ANALYZE FORMAT=JSON SELECT ...

EXPLAIN 输出说明

字段 说明
id 查询编号
select_type 查询类型
table 表名
type 访问类型
possible_keys 可能使用的索引
key 实际使用的索引
key_len 索引长度
ref 索引引用的列
rows 估算扫描行数
Extra 附加信息

type 访问类型(从好到差)

system > const > eq_ref > ref > range > index > ALL

4.10 本章小结

✅ 掌握 SELECT 基本查询和别名使用
✅ 熟练使用 WHERE 条件、LIKE 模糊匹配
✅ 理解 GROUP BY 分组和 HAVING 过滤
✅ 精通 INNER JOIN、LEFT JOIN 多表连接
✅ 学会使用子查询和 UNION 联合查询
✅ 掌握窗口函数进行排名和累计计算
✅ 善用 EXPLAIN 分析查询性能

📖 下章预告:索引原理与应用