-- 等于查询 SELECT*FROM employees WHERE department ='技术部';
-- 不等于查询 SELECT*FROM employees WHERE department !='技术部'; SELECT*FROM employees WHERE department <>'技术部';
-- 范围查询 SELECT*FROM employees WHERE salary BETWEEN5000AND10000;
-- 列表查询 SELECT*FROM employees WHERE department IN ('技术部', '销售部', '财务部');
-- NULL值查询 SELECT*FROM employees WHERE manager_id ISNULL; -- 查询没有上级的员工 SELECT*FROM employees WHERE email ISNOT NULL; -- 查询有邮箱的员工
-- 模糊查询 SELECT*FROM employees WHERE name LIKE'张%'; -- 以"张"开头 SELECT*FROM employees WHERE name LIKE'%张%'; -- 包含"张" SELECT*FROM employees WHERE name LIKE'_张%'; -- 第二个字是"张" SELECT*FROM employees WHERE name LIKE'张_'; -- 两个字,第一个是"张"
2.3 逻辑运算符
运算符
说明
示例
AND / &&
逻辑与
salary > 5000 AND department = '技术部'
OR / `
`
NOT / !
逻辑非
NOT (salary > 5000)
XOR
逻辑异或
salary > 5000 XOR department = '技术部'
逻辑运算示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-- AND:同时满足多个条件 SELECT*FROM employees WHERE salary >5000AND department ='技术部';
-- OR:满足任一条件 SELECT*FROM employees WHERE salary >10000OR position ='经理';
-- 以"张"开头 SELECT*FROM employees WHERE name LIKE'张%';
-- 以"张"结尾 SELECT*FROM employees WHERE name LIKE'%张';
-- 包含"张" SELECT*FROM employees WHERE name LIKE'%张%';
-- 第二个字是"张" SELECT*FROM employees WHERE name LIKE'_张%';
-- 名字是两个字,第一个是"张" SELECT*FROM employees WHERE name LIKE'张_';
-- 名字是三个字,第一个是"张" SELECT*FROM employees WHERE name LIKE'张__';
-- 使用正则表达式 SELECT*FROM employees WHERE name REGEXP '^张'; -- 以"张"开头 SELECT*FROM employees WHERE name REGEXP '张$'; -- 以"张"结尾 SELECT*FROM employees WHERE name REGEXP '^[0-9]'; -- 以数字开头
-- 隐式内连接(WHERE) SELECT e.name, d.department_name FROM employees e, departments d WHERE e.department_id = d.id;
-- 显式内连接(INNER JOIN)- 推荐 SELECT e.name, d.department_name FROM employees e INNERJOIN departments d ON e.department_id = d.id;
-- 内连接可以省略INNER SELECT e.name, d.department_name FROM employees e JOIN departments d ON e.department_id = d.id;
-- 多表内连接 SELECT e.name, d.department_name, p.project_name FROM employees e INNERJOIN departments d ON e.department_id = d.id INNERJOIN employee_projects ep ON e.id = ep.employee_id INNERJOIN projects p ON ep.project_id = p.id;
-- 使用USING(当连接字段名相同时) SELECT e.name, d.department_name FROM employees e INNERJOIN departments d USING(department_id);
-- 左连接:查询所有员工及其部门(包括没有部门的员工) SELECT e.name, d.department_name FROM employees e LEFTJOIN departments d ON e.department_id = d.id;
-- 左连接 + WHERE过滤:只显示左表中在右表没有匹配的记录 SELECT e.name, d.department_name FROM employees e LEFTJOIN departments d ON e.department_id = d.id WHERE d.id ISNULL; -- 找出没有部门的员工
-- 员工与上级的自连接 SELECT e.name AS employee_name, m.name AS manager_name FROM employees e LEFTJOIN employees m ON e.manager_id = m.id;
-- 分类与父分类的自连接 SELECT c.name AS category_name, p.name AS parent_name FROM categories c LEFTJOIN categories p ON c.parent_id = p.id;
-- 查找同一部门中工资比自己高的同事 SELECT e1.name, e1.salary, e2.name AS colleague_name, e2.salary AS colleague_salary FROM employees e1 INNERJOIN employees e2 ON e1.department_id = e2.department_id WHERE e1.salary < e2.salary;
4.7 交叉连接(CROSS JOIN)
返回笛卡尔积(两个表所有组合)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 显式交叉连接 SELECT e.name, d.department_name FROM employees e CROSSJOIN departments d;
-- 隐式交叉连接(不推荐) SELECT e.name, d.department_name FROM employees e, departments d;
-- 实际应用:生成所有组合 -- 例如:每个学生与每门课程的组合 SELECT s.name AS student, c.name AS course FROM students s CROSSJOIN courses c;
-- 1. 查询用户及其订单(左连接) SELECT u.name, o.order_no, o.total_amount FROM users u LEFTJOIN orders o ON u.id = o.user_id;
-- 2. 查询订单及用户信息(内连接) SELECT o.order_no, u.name, u.email, o.total_amount FROM orders o INNERJOIN users u ON o.user_id = u.id;
-- 3. 查询订单详情(三表连接) SELECT o.order_no, u.name, p.name AS product_name, oi.quantity, oi.price FROM orders o INNERJOIN users u ON o.user_id = u.id INNERJOIN order_items oi ON o.id = oi.order_id INNERJOIN products p ON oi.product_id = p.id;
-- 4. 查询没有下单的用户 SELECT u.name, u.email FROM users u LEFTJOIN orders o ON u.id = o.user_id WHERE o.id ISNULL;
-- 5. 查询每个用户的订单数量和总金额 SELECT u.name, COUNT(o.id) AS order_count, COALESCE(SUM(o.total_amount), 0) AS total_amount FROM users u LEFTJOIN orders o ON u.id = o.user_id GROUPBY u.id;
-- 6. 查询热销商品TOP 10 SELECT p.name, SUM(oi.quantity) AS total_sold, SUM(oi.quantity * oi.price) AS total_revenue FROM products p INNERJOIN order_items oi ON p.id = oi.product_id INNERJOIN orders o ON oi.order_id = o.id WHERE o.status IN ('已支付', '已完成') GROUPBY p.id ORDERBY total_sold DESC LIMIT 10;
-- 查询工资高于平均工资的员工 SELECT name, salary FROM employees WHERE salary > (SELECTAVG(salary) FROM employees);
-- 查询工资最高的员工 SELECT name, salary FROM employees WHERE salary = (SELECTMAX(salary) FROM employees);
-- 查询与"张三"同部门的员工 SELECT name, department_id FROM employees WHERE department_id = (SELECT department_id FROM employees WHERE name ='张三');
-- 查询部门人数最多的部门 SELECT department_id, COUNT(*) AS emp_count FROM employees GROUPBY department_id HAVINGCOUNT(*) = ( SELECTMAX(emp_count) FROM ( SELECTCOUNT(*) AS emp_count FROM employees GROUPBY department_id ) AS t );
-- 查询技术部和产品部的员工 SELECT name, department_id FROM employees WHERE department_id IN ( SELECT id FROM departments WHERE name IN ('技术部', '产品部') );
-- 查询有订单的用户 SELECT*FROM users WHERE id IN (SELECTDISTINCT user_id FROM orders);
-- 查询没有订单的用户 SELECT*FROM users WHERE id NOTIN (SELECTDISTINCT user_id FROM orders WHERE user_id ISNOT NULL);
-- 查询购买了"iPhone 15"的用户 SELECT*FROM users WHERE id IN ( SELECTDISTINCT o.user_id FROM orders o INNERJOIN order_items oi ON o.id = oi.order_id INNERJOIN products p ON oi.product_id = p.id WHERE p.name ='iPhone 15' );
-- 查询工资高于任意一个部门平均工资的员工 SELECT name, salary FROM employees WHERE salary >ANY ( SELECTAVG(salary) FROM employees GROUPBY department_id );
-- 等价于:大于最小平均值 SELECT name, salary FROM employees WHERE salary > ( SELECTMIN(avg_sal) FROM ( SELECTAVG(salary) AS avg_sal FROM employees GROUPBY department_id ) AS t );
-- 查询工资高于所有部门平均工资的员工 SELECT name, salary FROM employees WHERE salary >ALL ( SELECTAVG(salary) FROM employees GROUPBY department_id );
-- 等价于:大于最大平均值 SELECT name, salary FROM employees WHERE salary > ( SELECTMAX(avg_sal) FROM ( SELECTAVG(salary) AS avg_sal FROM employees GROUPBY department_id ) AS t );
-- = ANY 等同于 IN SELECT name FROM employees WHERE department_id =ANY (SELECT id FROM departments WHERE name LIKE'%部');
-- 等价于 SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE name LIKE'%部');
-- 非相关子查询:子查询独立执行 SELECT name FROM employees WHERE salary > (SELECTAVG(salary) FROM employees);
-- 相关子查询:子查询引用外层表的字段 SELECT e1.name, e1.salary, e1.department_id FROM employees e1 WHERE e1.salary > ( SELECTAVG(e2.salary) FROM employees e2 WHERE e2.department_id = e1.department_id -- 引用外层表 ); -- 相关子查询:对每个员工,计算其所在部门的平均工资,再比较
-- 相关子查询改写为JOIN(性能更好) SELECT e1.name, e1.salary, e1.department_id FROM employees e1 INNERJOIN ( SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUPBY department_id ) e2 ON e1.department_id = e2.department_id WHERE e1.salary > e2.avg_salary;
5.8 子查询在SELECT子句中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-- 查询员工信息及其部门平均工资 SELECT e.name, e.salary, e.department_id, (SELECTAVG(e2.salary) FROM employees e2 WHERE e2.department_id = e.department_id) AS dept_avg_salary FROM employees e;
-- 查询每个部门的员工数(使用子查询) SELECT d.name, (SELECTCOUNT(*) FROM employees e WHERE e.department_id = d.id) AS emp_count FROM departments d;
5.9 子查询在FROM子句中(派生表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-- 查询平均工资大于5000的部门 SELECT t.department_id, t.avg_salary FROM ( SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUPBY department_id ) t WHERE t.avg_salary >5000;
-- 配合WITH子句(MySQL 8.0+,公共表表达式CTE) WITH dept_avg AS ( SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUPBY department_id ) SELECT e.name, e.salary, d.avg_salary FROM employees e INNERJOIN dept_avg d ON e.department_id = d.department_id WHERE e.salary > d.avg_salary;
六、GROUP BY 分组查询
6.1 基本分组
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 按部门分组,统计每个部门的员工数 SELECT department_id, COUNT(*) AS emp_count FROM employees GROUPBY department_id;
-- 按部门分组,统计平均工资 SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUPBY department_id;
-- 多字段分组 SELECT department_id, position, COUNT(*) AS emp_count, AVG(salary) AS avg_salary FROM employees GROUPBY department_id, position;
6.2 HAVING 分组过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- HAVING:过滤分组后的结果 SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUPBY department_id HAVINGAVG(salary) >5000;
-- WHERE + GROUP BY + HAVING SELECT department_id, COUNT(*) AS emp_count FROM employees WHERE salary >3000-- 先过滤行 GROUPBY department_id HAVINGCOUNT(*) >5; -- 再过滤分组
-- 多条件过滤 SELECT department_id, AVG(salary) AS avg_salary, COUNT(*) AS emp_count FROM employees GROUPBY department_id HAVINGAVG(salary) >5000ANDCOUNT(*) >3;
6.3 WHERE vs HAVING
子句
作用
过滤对象
WHERE
过滤数据行
原始记录
HAVING
过滤分组
分组结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- WHERE:先过滤再分组 SELECT department_id, COUNT(*) AS emp_count FROM employees WHERE salary >5000-- 过滤工资>5000的员工 GROUPBY department_id;
-- HAVING:先分组再过滤 SELECT department_id, COUNT(*) AS emp_count FROM employees GROUPBY department_id HAVINGCOUNT(*) >5; -- 过滤员工数>5的部门
-- 组合使用 SELECT department_id, AVG(salary) AS avg_salary FROM employees WHERE status ='active'-- WHERE:过滤在职员工 GROUPBY department_id HAVINGAVG(salary) >5000; -- HAVING:过滤平均工资>5000的部门
6.4 GROUP BY + WITH ROLLUP
1 2 3 4 5 6 7 8 9 10 11 12 13
-- WITH ROLLUP:在结果中添加汇总行 SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary FROM employees GROUPBY department_id WITHROLLUP;
-- 普通分页(偏移量大时性能差) SELECT*FROM employees ORDERBY id LIMIT 100000, 10;
-- 优化1:使用WHERE条件过滤 SELECT*FROM employees WHERE id >100000 ORDERBY id LIMIT 10;
-- 优化2:使用JOIN(覆盖索引) SELECT e.* FROM employees e INNERJOIN ( SELECT id FROM employees ORDERBY id LIMIT 100000, 10 ) t ON e.id = t.id;
九、实战案例:复杂查询
9.1 案例一:销售排行榜
1 2 3 4 5 6 7 8 9 10 11 12
-- 查询销售额TOP 10的用户 SELECT u.id, u.name, COUNT(o.id) AS order_count, SUM(o.total_amount) AS total_amount FROM users u INNERJOIN orders o ON u.id = o.user_id WHERE o.status ='已完成' GROUPBY u.id ORDERBY total_amount DESC LIMIT 10;
9.2 案例二:部门薪资统计
1 2 3 4 5 6 7 8 9 10 11 12
-- 查询各部门薪资统计(平均工资、最高工资、最低工资、员工数) SELECT d.name AS department_name, COUNT(e.id) AS emp_count, ROUND(AVG(e.salary), 2) AS avg_salary, MAX(e.salary) AS max_salary, MIN(e.salary) AS min_salary, SUM(e.salary) AS total_salary FROM departments d LEFTJOIN employees e ON d.id = e.department_id GROUPBY d.id ORDERBY avg_salary DESC;
-- 查询商品本月销量与上月销量的对比 WITH this_month AS ( SELECT product_id, SUM(quantity) AS qty FROM order_items WHERE create_time >= DATE_FORMAT(NOW(), '%Y-%m-01') AND create_time < DATE_ADD(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL1MONTH) GROUPBY product_id ), last_month AS ( SELECT product_id, SUM(quantity) AS qty FROM order_items WHERE create_time >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL1MONTH), '%Y-%m-01') AND create_time < DATE_FORMAT(NOW(), '%Y-%m-01') GROUPBY product_id ) SELECT p.name AS product_name, COALESCE(t.qty, 0) AS this_month_qty, COALESCE(l.qty, 0) AS last_month_qty, CASE WHENCOALESCE(l.qty, 0) =0THEN'NEW' ELSE CONCAT(ROUND((COALESCE(t.qty, 0) - l.qty) / l.qty *100, 2), '%') ENDAS growth_rate FROM products p LEFTJOIN this_month t ON p.id = t.product_id LEFTJOIN last_month l ON p.id = l.product_id WHERECOALESCE(t.qty, 0) >0ORCOALESCE(l.qty, 0) >0;
💡 小结:本章详细介绍了 MySQL 的查询进阶知识,包括 SELECT 完整语法、各类运算符、WHERE 条件查询、多表连接查询、子查询与嵌套查询、GROUP BY 分组、ORDER BY 排序和 LIMIT 分页。掌握这些查询技巧后,可以应对绝大多数的数据库查询需求。