-- 一定要加 WHERE,除非你想删库跑路 UPDATE `users` SET `status` = 0 WHERE `username` = 'lisi'; -- 多列更新 UPDATE `users` SET `age` = 18, `email` = 'new@qq.com' WHERE `id` = 1;
DELETE(删除):
-- 逻辑删除优于物理删除(后端规范:增加 is_deleted 字段) DELETE FROM `users` WHERE `id` = 2; -- 推荐逻辑删除UPDATE users SET is_deleted = 1 WHERE id = 2;
2.3 DQL (Data Query Language) —— 数据查询语言(重点)
作用:从数据库中检索数据。后端 80% 的性能瓶颈在这里。
基础查询
-- 1. 简单查询与去重
SELECT username, age FROM users;
SELECT DISTINCT status FROM users; -- 去重
-- 2. 条件查询 (WHERE)
-- 注意:索引失效场景 (如 age+1 > 20 会使索引失效,应写成 age > 19)
SELECT * FROM users WHERE age > 20 AND status = 1;
SELECT * FROM users WHERE email IS NOT NULL; -- 判断空用 IS,不能用 = NULL
SELECT * FROM users WHERE username IN ('zhangsan', 'lisi');
-- 模糊查询 (以张开头,虽然以%开头会让索引失效,但业务中常需注意)
SELECT * FROM users WHERE username LIKE '张%';
分组与聚合 (GROUP BY + HAVING)
-- 聚合函数: COUNT, SUM, AVG, MAX, MIN
-- 需求:统计每个用户的订单总金额,且只显示订单总金额大于 100 的用户
SELECT
user_id,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
WHERE created_at > '2025-01-01' -- 分组前的条件过滤
GROUP BY user_id
HAVING total_amount > 100 -- 分组后的条件过滤(这里用了别名,MySQL特有)
ORDER BY total_amount DESC
LIMIT 10;
后端硬核提醒:WHERE 过滤行,HAVING 过滤组。能在 WHERE 中过滤的,绝不留到 HAVING(性能差异巨大)。
连接查询 (JOIN) —— 后端最易出错的地方
INNER JOIN(内连接):取交集。
LEFT JOIN(左连接):左表全量 + 右表匹配项(无则为 NULL)。
RIGHT JOIN(右连接):同左连接。
-- 需求:查询所有用户及其订单信息(没有下单的用户也要显示)
SELECT
u.id,
u.username,
o.id AS order_id,
o.amount,
o.product_name
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- 需求:查询下单超过 2 次的用户信息 (子查询 + JOIN)
SELECT u.*, t.order_count
FROM users u
INNER JOIN (
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 2
) t ON u.id = t.user_id;
子查询 (Subquery)
注意:MySQL 5.6 之后对子查询做了优化,但 EXISTS 和 IN 有区别:
IN:先执行子查询(内表),适合子查询结果集较小。
EXISTS:先执行外表,适合外表较小,内表巨大的情况(因为走索引)。
-- 查询所有下过单的用户 (IN)
SELECT * FROM users WHERE id IN (SELECT DISTINCT user_id FROM orders);
-- 查询没有下过单的用户 (NOT EXISTS 效率通常高于 NOT IN)
SELECT * FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
配合标量子查询常用的操作符有:= ,<> , > , >= , < , <=
配合列子查询常用的操作符有:in , not in等
配合行子查询常用的操作符有:= ,<> ,in , not in
配合行表查询常用的操作符有:in,常作为临时表使用
窗口函数 (Window Functions) —— MySQL 8.0+ 杀手锏
超级好用!解决“每组取前N条”的难题,告别复杂的临时表。
-- 需求:查询每个用户金额最高的前 2 个订单
WITH ranked_orders AS (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rn,
RANK() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rk, -- 有并列跳号
DENSE_RANK() OVER (PARTITION BY user_id ORDER BY amount DESC) AS dr -- 有并列不跳号
FROM orders
)
SELECT * FROM ranked_orders WHERE rn <= 2;
执行顺序图解 (极重要)
你在写 SQL 时脑子里必须过一遍这个执行顺序(注意是执行顺序不是编写顺序): FROM -> ON -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT
经典案例(别名报错原因):
-- 错误写法:WHERE 执行在 SELECT 之前,所以不知道 alias
SELECT amount + 1 AS new_amount FROM orders WHERE new_amount > 100; -- 报错!
-- 正确写法:用 HAVING 或 子查询
SELECT amount + 1 AS new_amount FROM orders HAVING new_amount > 100;
-- 或者套一层子查询 (推荐,逻辑清晰)
SELECT * FROM (SELECT amount + 1 AS new_amount FROM orders) t WHERE new_amount > 100;
2.4 DCL (Data Control Language) —— 数据控制语言
作用:管理数据库权限和安全性(通常由 DBA 或运维操作,后端了解即可)。
GRANT(授权): sql -- 授予 zhangjie 用户对 ecommerce 库所有表的 SELECT 和 INSERT 权限 GRANT SELECT, INSERT ON ecommerce.* TO 'zhangjie'@'localhost' IDENTIFIED BY 'password123';
REVOKE(收回): sql -- 收回 DELETE 权限 REVOKE DELETE ON ecommerce.* FROM 'zhangjie'@'localhost';
Comments NOTHING