MySQL必备基础

而本文的[sql操作],统一采用的是这里的数据。

(如果点击无效,可以直接翻到文章末尾,具体代码在文末)

DML-插入

1、一句话总结:在什么场景下,解决了什么问题

新增业务数据 (如注册用户、创建订单、写日志)场景下,insert 用来把新记录[持久化]到数据库,解决"数据从业务产生到落库保存"的问题。

2、2~4个关键词

insert into / values

3、2个基础,并直接能用的命令

sql 复制代码
-- 更新状态
-- 1) 单行插入:新增一个用户(注意:显式写列名,最稳)
insert into `user` (id, username, nickname, email, city, created_at, updated_at)
values (2002, 'mike', null, 'mike@example.com', 'Beijing', now(), now());

-- 2) 多行插入:一次插入多条日志(演示批量 values)
insert into `log` (id, level, message, created_at)
values
(60010, 'info', 'new log 1', now()),
(60011, 'warn', 'new log 2', now());

AI写代码sql
12345678910

4、1个坑,最容易翻车的点

不写列名导致列顺序一变就插错;最好永远写上列名。

DML-更新和删除

1、一句话总结:在什么场景下,解决了什么问题

改/删数据,用于修改业务状态。通过where 进行精确定位,避免误伤。

2、2~4个关键词

delete / update / where/ limit

3、2个基础,并直接能用的命令

sql 复制代码
-- 更新状态
update `orders`
set status = 'PAID'
where id = 50002;
-- 删除日志
delete from `log`
where created_at<NOW()-interval 30 day

AI写代码sql
1234567

4、1个坑,最容易翻车的点

delete中,漏写where,导致全表数据删除。

DQL-基础查询

1、一句话总结:在什么场景下,解决了什么问题

查数据并做列表,只拿需要的列 ,有条件,有分页。

2、2~4个关键词

select / distinct / 列投影 / as

3、2个基础,并直接能用的命令

sql 复制代码
select id,username from user;
select distinct city from user;

AI写代码sql
12

4、1个坑,最容易翻车的点

select * 在查询大表/宽表时很慢,并且容易触发回表网络IO

DQL-条件查询

1、一句话总结:在什么场景下,解决了什么问题

where 筛选,筛选出"我需要的数据"

2、2~4个关键词

where / like / or / between

3、2个基础,并直接能用的命令

sql 复制代码
-- 查今天已支付订单
SELECT * FROM `orders`
WHERE status='PAID' AND pay_time >= CURDATE();

-- 查 username 以 a 开头 或 指定 id 集合
SELECT * FROM `user`
WHERE username LIKE 'a%' OR id IN (1001,1002,1003);

AI写代码sql
1234567

4、1个坑,最容易翻车的点

null 不能用 " =null " ,而应该用 is null / is not null

DQL-聚合函数

1、一句话总结:在什么场景下,解决了什么问题

统计报表:总数,平均数,最大最小值

2、2~4个关键词

sum / avg / min / max

3、2个基础,并直接能用的命令

sql 复制代码
-- 总数
select count(*) from orders where status = 'PAID';
-- 分组+平均数
select dept_id,avg(salary) as avg_salary from emp group by dept_id;

AI写代码sql
1234

4、1个坑,最容易翻车的点

count(col) ,会忽略掉NULL值,所以用count(*),是最保底的选择。

DQL-分组查询

1、一句话总结:在什么场景下,解决了什么问题

分组聚合,并按 "维度查询 "

2、2~4个关键词

group by / having / 维度聚合

3、2个基础,并直接能用的命令

sql 复制代码
select city , count(*) from user group by city ;

select city , count(*) as c from user group by city having c>2;

AI写代码sql
123

4、1个坑,最容易翻车的点
where vs having:其中,where过滤的是行,而having过滤的是聚合后的结果

DQL-排序查询

1、一句话总结:在什么场景下,解决了什么问题

列表,按照时间、分数...排序

2、2~4个关键词

order by / desc / asc

3、2个基础,并直接能用的命令

sql 复制代码
select * from `post` order by created_at desc ;

select * from `post` order by score desc , created_at desc ;

AI写代码sql
123

4、1个坑,最容易翻车的点

大 OFFSET 排序很慢。(可以通过索引进行优化)

DQL-分页查询

1、一句话总结:在什么场景下,解决了什么问题

列表分页,解决 "只取一页的问题" 。

2、2~4个关键词

limit / offset / 深分页

3、2个基础,并直接能用的命令

sql 复制代码
select * from `post` order by id desc limit 5 offset 0;
-- 游标分页(直接确定id,然后往前翻)
select * from `post` where id<100000 order by id desc limit 3;

AI写代码sql
123

4、1个坑,最容易翻车的点

深分页,如offset=10000会抛弃大量行,所以推荐使用游标分页。

DQL-案例联系

1、一句话总结:在什么场景下,解决了什么问题

综合使用

2、2~4个关键词

组合查询 / 可读性 / 逐步验证

3、2个基础,并直接能用的命令

sql 复制代码
-- 例:查北京用户的已支付订单列表
SELECT o.id, o.amount, o.created_at, u.username
FROM `orders` o
JOIN `user` u ON o.user_id=u.id
WHERE u.city='Beijing' AND o.status='PAID'
ORDER BY o.created_at DESC
LIMIT 5;

EXPLAIN
SELECT o.id, o.amount, o.created_at, u.username
FROM `orders` o
JOIN `user` u ON o.user_id=u.id
WHERE u.city='Beijing' AND o.status='PAID'
ORDER BY o.created_at DESC
LIMIT 5;

AI写代码sql
123456789101112131415

4、1个坑,最容易翻车的点

不 explain 就上生产,就很容易写出慢查询

DQL-执行顺序

1、一句话总结:在什么场景下,解决了什么问题

解释,为什么别名能够在having 中用,而不能在where 中用。

2、2~4个关键词

from / where / limit / select / group by / having

3、2个基础,并直接能用的命令

sql 复制代码
select dept_id, count(*) as c
from emp
group by dept_id
having c>1;

AI写代码sql
1234

4、1个坑,最容易翻车的点

执行顺序
from > where > group by > having > select > order by > limit

原本按顺序,having应该也无法看到别名,但是mysql做了拓展。

DQL-小结

1、一句话总结:在什么场景下,解决了什么问题

查询 = "筛选(where)+聚合(group)+排序(order)+分页(limit)+索引(explain)"

2、2~4个关键词

explain 回表 索引

3、2个基础,并直接能用的命令

sql 复制代码
EXPLAIN SELECT ...;
--暂时,还没怎么用过
SHOW WARNINGS;(看优化器重写/警告)

AI写代码sql
123

4、1个坑,最容易翻车的点

只会写代码,而不会检查,非常掉分。

DCL-用户管理

1、一句话总结:在什么场景下,解决了什么问题

管理账号与登录来源,用最小的权限,隔离环境

2、2~4个关键词

create user / alter user / drop user

3、2个基础,并直接能用的命令

sql 复制代码
create user 'user'@'localhost' identified by '123456';

alter user 'user'@'localhost' identified by '1234';

AI写代码sql
123

4、1个坑,最容易翻车的点

'user'@'localhost' 与 'user'@'%'是两条不同的账户,经常配错,出现能连/不能连的问题。(需注意优先级)

DCL-权限控制

1、一句话总结:在什么场景下,解决了什么问题

控制谁,能对某些表,进行特定的权限操作。避免越权误删

2、2~4个关键词

grant / revoke / show grants

3、2个基础,并直接能用的命令

sql 复制代码
grant select,alter on interview_mysql.dept to 'user'@'localhost';
--展示权限
show grants for 'user'@'localhost'

AI写代码sql
123

4、1个坑,最容易翻车的点

直接给 grant all 是管理上的惰性,会给未来增加不可预测的风险。

DCL-小结

1、一句话总结:在什么场景下,解决了什么问题

账号="主题", 权限="动作+资源范围",原则="最小权限"

2、2~4个关键词

最小权限 / 审计 / 账号隔离

3、2个基础,并直接能用的命令

sql 复制代码
-- 删除
revoke select on interview_mysql.dept from 'user'@'localhost';
-- 刷新,并清空
flush privileges;

AI写代码sql
1234

4、1个坑,最容易翻车的点

误以为改了权限就会马上生效:alter/revoke在mysql中自动刷新,通常不需要flush。

函数-字符串函数

1、一句话总结:在什么场景下,解决了什么问题

清洗/格式化文本,拼接展示

2、2~4个关键词

concat / replace / substring / length

3、2个基础,并直接能用的命令

sql 复制代码
-- concat(..)组合
-- coalesce(..)选取第一个非空
select concat(username,'(',coalesce(nickname,'-'),')') as showName
from user;
--替换
select replace(email,'@example.com','@demo.com')
from user;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

length()统计长度,中文可能会变长。用char_length()更合适。

函数-数据函数

1、一句话总结:在什么场景下,解决了什么问题

做 金额/评分/统计 时,需要用到的数值处理

2、2~4个关键词

round / ceil/floor / abs / decimal

3、2个基础,并直接能用的命令

python 复制代码
select id,round(amount,2) as money
from orders;

select id,floor(amount),ceil(amount) as money
from orders;

AI写代码sql
12345

4、1个坑,最容易翻车的点

金额计算时别用浮点数存储,用decimal(10,2)-定点数,否则会有精度的坑。

函数-日期函数

1、一句话总结:在什么场景下,解决了什么问题

解决了数据分析时间报表 中,对时间的分析与处理。

2、2~4个关键词

interval / date / date_add / timestampdiff

3、2个基础,并直接能用的命令

sql 复制代码
select *
from orders
where created_at>now()-interval 7 day;

select date(created_at) as d ,count(*) as c
from orders
group by d
order by c
--计算时间差值(时间单位,time1,time2)
select timestampdiff(day,date(created_at),'2025-11-20') as diff
from orders

AI写代码sql
1234567891011

4、1个坑,最容易翻车的点

应用/DB 时区不一致会导致时间错位。可以统一时区,或者用UTC。

函数-流程函数

1、一句话总结:在什么场景下,解决了什么问题

在sql层,做简单的分支控制 / 空值处理 / 分类统计

2、2~4个关键词

case / coalesce / if / when

3、2个基础,并直接能用的命令

sql 复制代码
SELECT id, COALESCE(nickname, username) AS show_name
FROM `user`;

select
sum(case when status = 'PAID' then 1 else 0 end) as paid_status,
sum(case when status = 'CREATED' then 1 else 0 end) as created_status
from orders;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

case太复杂,会导致难以维护,应放在应用层。

约束-概述

1、一句话总结:在什么场景下,解决了什么问题

用约束保证数据的正确性:唯一/非空/范围...等等

2、2~4个关键词

primary key / unique / not null / check

3、2个基础,并直接能用的命令

sql 复制代码
show create table `user`;

show index from `user`;

AI写代码sql
123

4、1个坑,最容易翻车的点

只靠代码约束不保底;并发下需要数据库进行保底。

约束-外键约束

1、一句话总结:在什么场景下,解决了什么问题

保证 "子表引用父亲合理化" ,避免孤儿数据。

2、2~4个关键词

foreign key / 父子表 / 引用完整性

3、2个基础,并直接能用的命令

sql 复制代码
show create table `order_item`;

-- 触发外键:order_id 不存在(会报 cannot add or update a child row)
insert into `order_item`(id, order_id, product_name, price, qty, created_at)
values (79999, 99999, 'baditem', 1.00, 1, now());


AI写代码sql
123456

4、1个坑,最容易翻车的点

外键可能会带来写入约束影响。因此在高并发场景下可能会替换 掉约束。

约束-小结

1、一句话总结:在什么场景下,解决了什么问题

约束=数据库的最后一道防线,尤其主键/唯一/非空 这些是高频应用,而外键则需要另外考虑。

2、2~4个关键词

并发一致性 / 数据质量 / 兜底

3、2个基础,并直接能用的命令

sql 复制代码
show index from `orders`;
show create table `orders`;


AI写代码sql
123

4、1个坑,最容易翻车的点

没有约束,仅靠业务查重,在并发场景下必翻车(典型:"先查后插"竞态)

多表关系介绍

1、一句话总结:在什么场景下,解决了什么问题

关系:一对一/一对多/多对多,决定表结构与连接方式。

2、2~4个关键词

1:1 / 1:n / n:m / 中间表

3、2个基础,并直接能用的命令

sql 复制代码
-- 多对多 连表查询
select u.username, r.name as role_name
from `user_role` ur
join `user` u on ur.user_id = u.id
join `role` r on ur.role_id = r.id
where u.id = 1001;

-- 查看中间表
show create table `user_role`;


AI写代码sql
12345678910

4、1个坑,最容易翻车的点

多对多表格中,需要建立中间表。如果硬塞逗号隔开 = 灾难(无法索引,无法约束,难以维护),

多表查询概述

1、一句话总结:在什么场景下,解决了什么问题

把多个表拼接成一个结果集

2、2~4个关键词

join连接表 / on筛选条件

3、2个基础,并直接能用的命令

sql 复制代码
select o.id, u.username, o.status, o.amount
from `orders` o
join `user` u on o.user_id=u.id;

AI写代码sql
123

4、1个坑,最容易翻车的点

如果忘写on 或者条件写错,会导致笛卡尔积,结果爆炸且超慢。

内连接

1、一句话总结:在什么场景下,解决了什么问题

只要两边都匹配的记录:最常见的业务联表(inner join = join)

2、2~4个关键词

inner join / 等值连接

3、2个基础,并直接能用的命令

sql 复制代码
select o.id, u.username
from `orders` o
inner join `user` u on o.user_id = u.id;

select o.id, u.username
from `orders` o 
join `user` u on o.user_id = u.id;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

列名冲突,一定要用o.id,否则会造成不同表格之间的列名冲突。

外连接

1、一句话总结:在什么场景下,解决了什么问题

保留一侧:"用户列表+是否下过订单"

2、2~4个关键词

left join / right join

3、2个基础,并直接能用的命令

sql 复制代码
-- 主表为:user,主表
select u.id, u.username, o.id as order_id
from `user` u
left join `orders` o on u.id = o.user_id;

-- 只保留那些「没有任何订单匹配」的用户
select u.*
from `user` u
left join `orders` o on u.id = o.user_id
where o.id is null;


AI写代码sql
1234567891011

4、1个坑,最容易翻车的点

把右表on内的 匹配条件,写到where中,会把left join 变成 inner join。

因为on决定是如何匹配 ,而where决定的是那些行能活下来

自连接

1、一句话总结:在什么场景下,解决了什么问题

一张表自己连自己:一般用于 组织关系/上下级/...

2、2~4个关键词

层级关系 / 别名

3、2个基础,并直接能用的命令

csharp 复制代码
select e.name as emp_name, m.name as manager_name
from `emp` e
left join `emp` m on e.manager_id = m.id;

select *
from `emp`
where manager_id is null;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

别名起的不好,就会错列;自连接必须全程通过别名区分。

联合查询 union

1、一句话总结:在什么场景下,解决了什么问题

把两条查询上下拼接成一张结果(字段数与类型要对齐)

2、2~4个关键词

union 去重 / union all 不去重

3、2个基础,并直接能用的命令

sql 复制代码
-- 去重
select id from `t_a`
union
select id from `t_b`;
-- 不去重
select id from `t_a`
union all
select id from `t_b`;

AI写代码sql
12345678

4、1个坑,最容易翻车的点

默认union会去重,稍慢。所以能用union all尽量就用这个。

子查询

1、一句话总结:在什么场景下,解决了什么问题

把一个查询的结果当成另一个查询的条件/表;常用于"先算出集合再过滤"

2、2~4个关键词

in / exists

3、2个基础,并直接能用的命令

sql 复制代码
-- r&d 部门的员工
select * from `emp`
where dept_id in (select id from `dept` where name = 'r&d');

-- exists 写法
select * from `emp` e
where exists (
    select 1
    from `dept` d
    where d.id = e.dept_id
      and d.name = 'r&d'
);

AI写代码sql
123456789101112

4、1个坑,最容易翻车的点

子查询不一定慢,但相关子查询写不好会重复执行;能 JOIN 时也要会解释取舍。

标量子查询

1、一句话总结:在什么场景下,解决了什么问题

子查询返回单个值:用于"和某个统计值比较"。

2、2~4个关键词

scalar / 标量 / 聚合比较

3、2个基础,并直接能用的命令

sql 复制代码
SELECT * FROM `emp`
WHERE salary > (SELECT AVG(salary) FROM `emp`);

SELECT * FROM `orders`
WHERE amount = (SELECT MAX(amount) FROM `orders`);

AI写代码sql
12345

4、1个坑,最容易翻车的点

子查询返回多行会报错:Subquery returns more than 1 row,必须保证唯一加聚合 / limit

列子查询

1、一句话总结:在什么场景下,解决了什么问题

子查询返回一列多行:用于 IN/ANY/ALL。

2、2~4个关键词

in / any / all

3、2个基础,并直接能用的命令

sql 复制代码
select * from `emp`
where dept_id in(select id from `dept` where city = 'beijing');

select * from `emp`
where salary > all(select salary from `emp` where dept_id = 10);


AI写代码sql
123456

4、1个坑,最容易翻车的点

in 遇到 null 可能让逻辑变怪;必要时用 exists 更稳。

因为 sql 不是"二值逻辑",而是"三值逻辑":true / false / unknown(未知)。

可以动手看看,这个简单的例子:

csharp 复制代码
--这样没啥问题
select* from `emp`
where id in (null,1,2);

真正会把你坑惨的,是 not in + null
select* from `emp`
where id not in (null,1,2);
明明有好几行符合条件的,却一行都不会返回!!

AI写代码sql
12345678

行子查询

1、一句话总结:在什么场景下,解决了什么问题

自查询返回一行多列

2、2~4个关键词

row constructor / 多列比较

3、2个基础,并直接能用的命令

sql 复制代码
select * from `emp`
where (dept_id, job) = (select dept_id, job from `emp` where id = 2);

AI写代码sql
12

4、1个坑,最容易翻车的点

复合列要有合适联合索引,不然容易全表扫。

表子查询

1、一句话总结:在什么场景下,解决了什么问题

把子查询当作临时表 (派生表),在 join / 过滤

2、2~4个关键词

临时表 / derived table

3、2个基础,并直接能用的命令

vbnet 复制代码
select x.dept_id, x.c
from (select dept_id, count(*) as c from emp group by dept_id) x
where x.c > 2;

select y.user_id, y.total_amount
from (select user_id, sum(amount) as total_amount from orders group by user_id) y
order by y.total_amount desc
limit 5; 

AI写代码sql
12345678

4、1个坑,最容易翻车的点

派生表可能物化到临时表,数据量大很慢;尽量让派生表可被优化(字段少、条件早过滤)。

事务简介

1、一句话总结:在什么场景下,解决了什么问题

事务,用于把多步操作,变成"一同成功,或一同失败"

2、2~4个关键词

transaction / commit / rollback

3、2个基础,并直接能用的命令

sql 复制代码
start transaction;
commit;
-- 或
rollback;

AI写代码sql
1234

4、1个坑,最容易翻车的点

MySQL 默认 autocommit=1,你以为在事务里其实不是;要么显式开启,要么在框架里确认。

事务演示

1、一句话总结:在什么场景下,解决了什么问题

必知步骤:开启事务 -> 更新 -> 异常回滚 -> 保证了一致性

2、2~4个关键词

锁 / 回滚 / 一致性

3、2个基础,并直接能用的命令

sql 复制代码
--开启事务
start transaction;

update `account` set balance=balance-100, updated_at=now() where id=9001;
update `account` set balance=balance+100, updated_at=now() where id=9002;
--提交
commit;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

表引擎不是 InnoDB(如 MyISAM)不支持事务;面试一问就中招。

ACID四大特性

1、一句话总结:在什么场景下,解决了什么问题

用 ACID 解释"为什么事务可靠":原子/一致/隔离/持久。

2、2~4个关键词

Atomic / Consistent / Isolated / Durable

3、2个基础,并直接能用的命令

sql 复制代码
-- 查看是否开启自动提交
select @@autocommit;
-- 查看隔离程度
show variables like 'transaction_isolation';

AI写代码sql
1234

4、1个坑,最容易翻车的点

你说"有事务就绝对一致"不严谨:一致性还依赖约束、正确的业务逻辑与隔离级别。

并发事务问题

1、一句话总结:在什么场景下,解决了什么问题

并发下会出现:脏读、不可重复读、幻读。

2、2~4个关键词

dirty read / non-repeatable / phantom

3、2个基础,并直接能用的命令

arduino 复制代码
set session transaction isolation level read committed;

set session transaction isolation level repeatable read;

AI写代码sql
123

4、1个坑,最容易翻车的点

MySQL InnoDB 在 RR 隔离级别下,普通查询通过 MVCC 保证可重复读并避免幻读;而在范围更新或锁定读中,会通过行锁和间隙锁(Next-Key Lock)防止幻读,但这也可能导致范围锁定,从而引发意料之外的锁等待。

隔离级别

1、一句话总结:在什么场景下,解决了什么问题

不同的隔离级别,解决了什么问题?代价是什么?

2、2~4个关键词

RU / RC / RR / SERIALIZABLE / MVCC

3、2个基础,并直接能用的命令

sql 复制代码
start transaction;
select * from `account` where id=9001 for update;

-- 另一个会话可用共享锁读(mysql8 推荐 for share)
select * from `account` where id=9001 for share;
-- 提交/回滚释放锁
commit;

AI写代码sql
1234567

4、1个坑,最容易翻车的点

for update 在无索引条件下可能锁全表/大量行;一定要让 where 走索引。

实验数据,可直接插入mysql

sql 复制代码
-- =========================================================
MySQL 8(InnoDB + utf8mb4)
-- =========================================================

DROP DATABASE IF EXISTS interview_mysql;
CREATE DATABASE interview_mysql
  DEFAULT CHARACTER SET utf8mb4
  COLLATE utf8mb4_0900_ai_ci;
USE interview_mysql;

-- 关闭安全更新(练习 UPDATE/DELETE 时更方便;生产不建议)
SET SESSION sql_safe_updates = 0;

-- -----------------------
-- 清理旧表(按外键依赖顺序)
-- -----------------------
DROP TABLE IF EXISTS order_item;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS post;
DROP TABLE IF EXISTS user_role;
DROP TABLE IF EXISTS role;
DROP TABLE IF EXISTS account;
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
DROP TABLE IF EXISTS log;
DROP TABLE IF EXISTS t_a;
DROP TABLE IF EXISTS t_b;
DROP TABLE IF EXISTS user;

-- -----------------------
-- 1) 用户表(DQL / NULL / 字符串函数)
-- -----------------------
CREATE TABLE user (
  id         BIGINT PRIMARY KEY,
  username   VARCHAR(32) NOT NULL UNIQUE,
  nickname   VARCHAR(32) NULL,
  email      VARCHAR(64) NOT NULL UNIQUE,
  city       VARCHAR(32) NOT NULL,
  created_at DATETIME NOT NULL,
  updated_at DATETIME NOT NULL,
  INDEX idx_user_city (city),
  INDEX idx_user_created (created_at)
) ENGINE=InnoDB;

-- -----------------------
-- 2) 角色表 + 多对多中间表(多表/约束)
-- -----------------------
CREATE TABLE role (
  id   INT PRIMARY KEY,
  name VARCHAR(32) NOT NULL UNIQUE
) ENGINE=InnoDB;

CREATE TABLE user_role (
  user_id BIGINT NOT NULL,
  role_id INT NOT NULL,
  PRIMARY KEY (user_id, role_id),
  CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES user(id),
  CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES role(id)
) ENGINE=InnoDB;

-- -----------------------
-- 3) 部门/员工(JOIN + 自连接 + 聚合)
-- -----------------------
CREATE TABLE dept (
  id   INT PRIMARY KEY,
  name VARCHAR(32) NOT NULL UNIQUE,
  city VARCHAR(32) NOT NULL
) ENGINE=InnoDB;

CREATE TABLE emp (
  id         INT PRIMARY KEY,
  name       VARCHAR(32) NOT NULL,
  dept_id    INT NOT NULL,
  manager_id INT NULL,
  job        VARCHAR(32) NOT NULL,
  salary     DECIMAL(10,2) NOT NULL,
  hired_at   DATE NOT NULL,
  CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES dept(id),
  CONSTRAINT fk_emp_mgr  FOREIGN KEY (manager_id) REFERENCES emp(id),
  INDEX idx_emp_dept (dept_id),
  INDEX idx_emp_mgr (manager_id),
  INDEX idx_emp_salary (salary)
) ENGINE=InnoDB;

-- -----------------------
-- 4) 账户表(事务转账练习)
-- -----------------------
CREATE TABLE account (
  id         BIGINT PRIMARY KEY,
  user_id    BIGINT NOT NULL UNIQUE,
  balance    DECIMAL(12,2) NOT NULL,
  updated_at DATETIME NOT NULL,
  CONSTRAINT fk_acc_user FOREIGN KEY (user_id) REFERENCES user(id),
  INDEX idx_acc_balance (balance)
) ENGINE=InnoDB;

-- -----------------------
-- 5) 订单/明细(JOIN / 外键 / 分组统计 / NULL pay_time)
-- -----------------------
CREATE TABLE orders (
  id         BIGINT PRIMARY KEY,
  user_id    BIGINT NOT NULL,
  status     VARCHAR(16) NOT NULL,  -- CREATED/PAID/CANCELLED/REFUNDED
  amount     DECIMAL(12,2) NOT NULL,
  created_at DATETIME NOT NULL,
  pay_time   DATETIME NULL,
  updated_at DATETIME NOT NULL,
  CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES user(id),
  INDEX idx_orders_user (user_id),
  INDEX idx_orders_status_time (status, created_at),
  INDEX idx_orders_paytime (pay_time)
) ENGINE=InnoDB;

CREATE TABLE order_item (
  id           BIGINT PRIMARY KEY,
  order_id     BIGINT NOT NULL,
  product_name VARCHAR(64) NOT NULL,
  price        DECIMAL(12,2) NOT NULL,
  qty          INT NOT NULL,
  created_at   DATETIME NOT NULL,
  CONSTRAINT fk_item_order FOREIGN KEY (order_id) REFERENCES orders(id),
  INDEX idx_item_order (order_id)
) ENGINE=InnoDB;

-- -----------------------
-- 6) 帖子表(排序/分页/统计)
-- -----------------------
CREATE TABLE post (
  id         BIGINT PRIMARY KEY,
  user_id    BIGINT NOT NULL,
  title      VARCHAR(128) NOT NULL,
  score      INT NOT NULL,
  created_at DATETIME NOT NULL,
  CONSTRAINT fk_post_user FOREIGN KEY (user_id) REFERENCES user(id),
  INDEX idx_post_score_time (score, created_at),
  INDEX idx_post_user (user_id)
) ENGINE=InnoDB;

-- -----------------------
-- 7) 日志表(DML 删除练习:清理 30 天前)
-- -----------------------
CREATE TABLE log (
  id         BIGINT PRIMARY KEY,
  level      VARCHAR(8) NOT NULL,
  message    VARCHAR(255) NOT NULL,
  created_at DATETIME NOT NULL,
  INDEX idx_log_time (created_at),
  INDEX idx_log_level (level)
) ENGINE=InnoDB;

-- -----------------------
-- 8) UNION 练习用表
-- -----------------------
CREATE TABLE t_a (
  id INT PRIMARY KEY
) ENGINE=InnoDB;

CREATE TABLE t_b (
  id INT PRIMARY KEY
) ENGINE=InnoDB;

-- =========================================================
-- 插入数据
-- =========================================================

-- users(含 nickname NULL、不同城市、不同时间)
INSERT INTO user (id, username, nickname, email, city, created_at, updated_at) VALUES
(1001,'alice',  '阿丽',   'alice@example.com',   'Beijing',   '2025-11-01 10:00:00','2025-12-10 09:10:00'),
(1002,'bob',    NULL,     'bob@example.com',     'Beijing',   '2025-11-05 11:00:00','2025-12-11 12:00:00'),
(1003,'carol',  '小C',    'carol@example.com',   'Shanghai',  '2025-10-20 09:30:00','2025-12-09 08:00:00'),
(1004,'dave',   NULL,     'dave@example.com',    'Shanghai',  '2025-11-12 16:20:00','2025-12-12 19:00:00'),
(1005,'erin',   'E宝',    'erin@example.com',    'Shenzhen',  '2025-11-18 14:00:00','2025-12-13 10:01:00'),
(1006,'frank',  NULL,     'frank@example.com',   'Shenzhen',  '2025-11-21 17:45:00','2025-12-13 17:45:00'),
(1007,'grace',  '小G',    'grace@example.com',   'Guangzhou', '2025-10-01 08:00:00','2025-12-01 08:00:00'),
(1008,'henry',  NULL,     'henry@example.com',   'Guangzhou', '2025-09-15 09:00:00','2025-11-30 10:00:00'),
(1009,'ivy',    'Ivy',    'ivy@example.com',     'Hangzhou',  '2025-11-30 20:00:00','2025-12-12 20:00:00'),
(1010,'jack',   NULL,     'jack@example.com',    'Hangzhou',  '2025-12-01 09:00:00','2025-12-13 09:00:00'),
(1011,'kate',   'K',      'kate@example.com',    'Beijing',   '2025-10-10 10:10:10','2025-12-13 23:59:00'),
(1012,'leo',    NULL,     'leo@example.com',     'Shanghai',  '2025-12-05 12:12:12','2025-12-12 12:12:12');

-- roles
INSERT INTO role (id, name) VALUES
(1,'admin'),
(2,'merchant'),
(3,'customer');

-- user_role(多对多)
INSERT INTO user_role (user_id, role_id) VALUES
(1001,1),(1001,3),
(1002,3),
(1003,2),(1003,3),
(1004,3),
(1005,2),
(1006,3),
(1007,3),
(1008,3),
(1009,3),
(1010,3),
(1011,1),
(1012,3);

-- dept
INSERT INTO dept (id, name, city) VALUES
(10,'R&D','Beijing'),
(20,'Sales','Shanghai'),
(30,'Ops','Shenzhen');

-- emp(自连接:先插 manager,再插下属)
INSERT INTO emp (id, name, dept_id, manager_id, job, salary, hired_at) VALUES
(1,'ZhangBoss', 10, NULL,'Director', 35000.00,'2022-01-01'),
(2,'LiDev',      10, 1,   'Backend',  22000.00,'2023-03-15'),
(3,'WangDev',    10, 1,   'Backend',  21000.00,'2023-06-01'),
(4,'ChenQA',     10, 1,   'QA',       18000.00,'2024-02-20'),
(5,'ZhaoSales',  20, NULL,'Manager',  26000.00,'2021-09-10'),
(6,'SunSales',   20, 5,   'Sales',    16000.00,'2024-05-01'),
(7,'WuOps',      30, NULL,'Manager',  24000.00,'2022-11-11'),
(8,'HeSRE',      30, 7,   'SRE',      20000.00,'2024-08-08');

-- account(事务练习:转账)
INSERT INTO account (id, user_id, balance, updated_at) VALUES
(9001,1001,1000.00,'2025-12-13 10:00:00'),
(9002,1002, 250.50,'2025-12-13 10:00:00'),
(9003,1003,  88.80,'2025-12-13 10:00:00'),
(9004,1004, 500.00,'2025-12-13 10:00:00'),
(9005,1005, 999.99,'2025-12-13 10:00:00'),
(9006,1006,  10.00,'2025-12-13 10:00:00'),
(9007,1007,  66.66,'2025-12-13 10:00:00'),
(9008,1008,  77.77,'2025-12-13 10:00:00'),
(9009,1009, 300.00,'2025-12-13 10:00:00'),
(9010,1010, 120.00,'2025-12-13 10:00:00'),
(9011,1011,8888.88,'2025-12-13 10:00:00'),
(9012,1012,  15.00,'2025-12-13 10:00:00');

-- orders(包含:已支付/未支付/取消/退款;也包含"无明细订单"用于 LEFT JOIN)
INSERT INTO orders (id, user_id, status, amount, created_at, pay_time, updated_at) VALUES
(50001,1001,'PAID',      128.00,'2025-12-01 10:00:00','2025-12-01 10:02:00','2025-12-01 10:02:00'),
(50002,1001,'CREATED',    66.60,'2025-12-10 12:00:00',NULL,                 '2025-12-10 12:00:00'),
(50003,1002,'PAID',       19.90,'2025-12-02 09:00:00','2025-12-02 09:01:00','2025-12-02 09:01:00'),
(50004,1003,'CANCELLED',  58.00,'2025-11-20 18:30:00',NULL,                 '2025-11-20 18:45:00'),
(50005,1003,'PAID',      199.00,'2025-12-05 20:00:00','2025-12-05 20:10:00','2025-12-05 20:10:00'),
(50006,1004,'REFUNDED',   88.00,'2025-11-28 13:00:00','2025-11-28 13:05:00','2025-11-30 09:00:00'),
(50007,1005,'PAID',      520.00,'2025-12-11 11:11:11','2025-12-11 11:12:00','2025-12-11 11:12:00'),
(50008,1006,'CREATED',    39.90,'2025-12-12 15:00:00',NULL,                 '2025-12-12 15:00:00'),
(50009,1009,'PAID',       15.00,'2025-12-03 08:00:00','2025-12-03 08:00:30','2025-12-03 08:00:30'),
(50010,1010,'PAID',       88.88,'2025-12-13 09:09:09','2025-12-13 09:10:00','2025-12-13 09:10:00');

-- order_item(50002/50008 故意不给明细;练习"找无明细订单")
INSERT INTO order_item (id, order_id, product_name, price, qty, created_at) VALUES
(70001,50001,'Keyboard', 128.00,1,'2025-12-01 10:00:10'),
(70002,50003,'Notebook',  19.90,1,'2025-12-02 09:00:10'),
(70003,50005,'Monitor',  199.00,1,'2025-12-05 20:00:10'),
(70004,50006,'Mouse',     88.00,1,'2025-11-28 13:00:10'),
(70005,50007,'Phone',    520.00,1,'2025-12-11 11:11:20'),
(70006,50009,'Cable',     15.00,1,'2025-12-03 08:00:10'),
(70007,50010,'Headset',   88.88,1,'2025-12-13 09:09:20');

-- posts(用于 ORDER BY / LIMIT / GROUP BY / HAVING)
INSERT INTO post (id, user_id, title, score, created_at) VALUES
(80001,1001,'MySQL 基础复盘',        98,'2025-12-01 09:00:00'),
(80002,1001,'JOIN 面试题整理',        88,'2025-12-06 09:00:00'),
(80003,1002,'分页优化:深分页到游标', 95,'2025-12-10 21:00:00'),
(80004,1003,'事务与锁:RR 是否幻读',  93,'2025-12-08 20:00:00'),
(80005,1003,'EXPLAIN 怎么看',         80,'2025-11-22 10:00:00'),
(80006,1004,'子查询与 EXISTS 对比',    70,'2025-12-02 19:00:00'),
(80007,1005,'外键要不要上生产',        85,'2025-12-03 13:00:00'),
(80008,1006,'字符串函数清洗数据',      60,'2025-12-04 14:00:00'),
(80009,1007,'GROUP BY + HAVING 实战',  92,'2025-12-05 16:00:00'),
(80010,1008,'慢查询排查流程',          99,'2025-12-07 18:00:00'),
(80011,1009,'NULL 处理:COALESCE',     75,'2025-12-09 08:00:00'),
(80012,1010,'UNION vs UNION ALL',     65,'2025-12-12 08:30:00');

-- log(包含 30 天前的记录,练习 DELETE)
INSERT INTO log (id, level, message, created_at) VALUES
(60001,'INFO','service started',                '2025-12-13 10:00:00'),
(60002,'WARN','slow query detected',            '2025-12-12 11:00:00'),
(60003,'ERROR','db connection timeout',         '2025-12-11 12:00:00'),
(60004,'INFO','daily job finished',             '2025-11-10 09:00:00'),
(60005,'INFO','old log for cleanup (40d ago)',  '2025-11-01 00:00:00'),
(60006,'INFO','old log for cleanup (70d ago)',  '2025-10-05 00:00:00');

-- UNION 练习数据
INSERT INTO t_a (id) VALUES (1),(2),(3),(10);
INSERT INTO t_b (id) VALUES (3),(4),(5),(10);

-- =========================================================
-- (可选)快速自检:确认数据量
-- =========================================================
-- SELECT COUNT(*) AS users FROM user;
-- SELECT status, COUNT(*) FROM orders GROUP BY status;
-- SELECT city, COUNT(*) FROM user GROUP BY city;


AI写代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291

本文为最小可复用笔记。

相关推荐
Java水解2 小时前
Spring AOP原理深度解析:代理模式、JDK动态代理与CGLIB
后端·spring
无限大63 小时前
为什么显示器分辨率越高越清晰?——从像素到 4K/8K 的视觉革命
后端
阿苟3 小时前
nginx部署踩坑
前端·后端
ChineHe3 小时前
Gin框架基础篇001_路由与路由组详解
后端·golang·gin
神奇小汤圆3 小时前
深入理解Linux IPIP隧道:原理、配置与实战
后端
计算机毕设VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue酒店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
laozhoy13 小时前
深入理解Go语言errors.As方法:灵活的错误类型识别
开发语言·后端·golang
周杰伦_Jay3 小时前
【Go 语言】核心特性、基础语法及面试题
开发语言·后端·golang
czlczl200209254 小时前
Spring Boot 参数校验进阶:抛弃复杂的 Group 分组,用 @AssertTrue 实现“动态逻辑校验”
java·spring boot·后端