一、基础概念
数据库:DataBase(DB),是存储和管理数据的仓库。
数据库管理系统:DataBase Management System(DBMS),操纵和管理数据库的大型软件。
SQL:Structured Query Language,操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。
1.2 下载与连接
- 语法:mysql –u用户名 –p密码 [-h数据库服务器IP地址 -P端口号]
二、SQL 语句
- 介绍
| 分类 | 全称 | 说明 |
|---|---|---|
| DDL | Data Definition Language | 数据定义语言,用来定义数据库对象(数据库,表,字段) |
| DML | Data Manipulation Language | 数据操作语言,用来对数据库表中的数据进行增删改 |
| DQL | Data Query Language | 数据查询语言,用来查询数据库中表的记录 |
| DCL | Data Control Language | 数据控制语言,用来创建数据库用户、控制数据库的访问权限 |
2.1 DDL
2.1.1 创建数据库
- 语法
-- 查询所有数据库 show databases; -- 查询当前数据库 select database(); -- 使用/切换数据库 use 数据库名; -- 创建数据库 create database [if not exists] 数据库名 [default charset utf8mb4]; -- 删除数据库 drop database [if exists] 数据库名; - 例子
-- eg. 创建一个名字为: db_springboot 的数据库 create database db_springboot;
2.1.2 创建表
- 语法
create table 表名字( 字段1 字段类型 [约束] [comment 字段1注释], ...... 字段2 字段类型 [约束] [comment 字段2注释] ) [comment 表注释]; - 字段类型介绍:(这里只介绍常用的几个数据类型)
1° 数值类型
| 类型 | 大小(byte) | 有符号(SIGNED)范围 | 无符号(UNSIGNED)范围 | 描述 |
|---|---|---|---|---|
| tinyint | 1 | (-128,127) | (0,255) | 小整数值 |
| int | 4 | (-2147483648,2147483647) | (0,4294967295) | 大整数值 |
| bigint | 8 | (-2^63^,2^63^-1) | (0,2^64^-1) | 极大整数值 |
数值类型的选取原则: 在满足业务需求的前提下, 尽可能选择占用磁盘空间小的数据类型:
```sql
-- 年龄字段,年龄在0-255岁之间,则使用tinyint, 且年龄无负数,使用unsigned
age tinyint unsigned
-- id 字段一般业务使用 int 就足够了,int 类型已经可以表示42亿条数据了。
id int unsigned
```
**2° 字符串类型**
| 类型 | 大小 | 描述 |
|---|---|---|
| char | 0-255 bytes | 定长字符串 |
| varchar | 0-65535 bytes | 变长字符串 |
| 区别 | 优势 | 劣势 |
|---|---|---|
| char(10): 固定占用10个字符空间; 存储A, 占用10个空间; 存储ABC, 占用10个空间; | 性能略高 | 浪费磁盘空间 |
| varchar(10): 最多占用10个字符空间; 存储A, 占用1个空间; 存储ABC, 占用3个空间; | 节约磁盘空间 | 性能略低 |
```sql
-- 用户名长度不固定,则使用varchar(50), 用户名最长为50位。
username varchar(50)
-- 身份证号固定18位,则使用char(18)
idcard char(18)
-- 手机号固定11位,则使用char(11)
phone char(11)
```
**3° 日期类型**
</code></pre>
<table>
<thead>
<tr>
<th>类型</th>
<th>大小(byte)</th>
<th>范围</th>
<th>格式</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>date</td>
<td>3</td>
<td>1000-01-01 至 9999-12-31</td>
<td>YYYY-MM-DD</td>
<td>日期值,包括 (年-月-日)</td>
</tr>
<tr>
<td>datetime</td>
<td>8</td>
<td>1000-01-01 00:00:00 至 9999-12-31 23:59:59</td>
<td>YYYY-MM-DD HH:MM:SS</td>
<td>混合日期和时间值,包括 (年-月-日 时:分:秒)</td>
</tr>
</tbody>
</table>
<pre><code>```sql
-- 生日只需要 年-月-日, 则使用 date
bithday date
-- 创建时间和最后一个更新时间需要精确到 时:分:秒,则使用datetime
create_time datetime
update_time datetime
```
</code></pre>
<p>
```
- 约束介绍:
约束
描述
关键字
非空约束
限制该字段值不能为null
not null
唯一约束
保证字段的所有数据都是唯一、不重复的
unique
主键约束
主键是一行数据的唯一标识,要求非空且唯一
primary key
默认约束
保存数据时,如果未指定该字段值,则采用默认值
default
外键约束
让两张表的数据建立连接,保证数据的一致性和完整性
foreign key
- 例子:
tb_student 表说明:
字段名
类型
说明
id
int unsigned
主键,自增,唯一标识每条学生记录
student_id
char(8)
学号,非空,唯一,固定8位学号
name
varchar(50)
姓名,非空
gender
char(3)
性别,非空,0-薛定谔的猫,1-男,2-女, 默认值为:0
age
tinyint unsigned
年龄
enrollment_date
date
学籍注册日期(入学时间),非空
create_time
datetime
创建时间,非空,默认值为:当前系统时间
update_time
datetime
最后更新时间,非空,默认值为:当前系统时间
-- eg. 创建一个学生表 tb_student,字段说明剑上述表格
create table if not exists tb_student (
id int unsigned primary key auto_increment comment '主键,自增,唯一标识每条学生记录',
student_id char(8) not null unique comment '学号,非空,唯一,固定8位学号',
name varchar(50) not null comment '姓名,非空',
gender char(3) not null default '0' comment '性别,非空,0-薛定谔的猫,1-男,2-女,默认值为: 0',
age tinyint unsigned comment '年龄',
enrollment_date date not null comment '学籍注册日期(入学时间),非空',
create_time datetime not null default current_timestamp comment '创建时间,非空,默认值为: 当前系统时间',
update_time datetime not null default current_timestamp on update current_timestamp comment '最后更新时间,非空,默认值为: 当前系统时间'
) comment='学生信息表';
2.1.3 修改表结构
- 语法:
-- 查询当前数据库的所有表
show tables;
-- 查询表结构,desc (describe)
desc 表名;
-- 查询建表语句
show create table 表名;
-- 添加字段
alter table 表名 add 字段名 类型(长度) [comment 注释] [约束];
-- 修改字段类型
alter table 表名 modify 字段名 新数据类型(长度);
-- 修改字段名与字段类型
alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释] [约束];
-- 删除字段
alter table 表名 drop column 字段名;
-- 修改表名
alter table 表名 rename to 新表名;
-- 删除表
drop table [if exists] 表名;
2.2 DML
2.2.1 insert 插入数据
- 语法
-- 指定字段添加数据
insert into 表名 (字段名1, 字段名2) values (值1, 值2);
-- 全部字段添加数据
insert into 表名 values (值1, 值2, ...);
-- 批量添加数据(指定字段)
insert into 表名 (字段名1, 字段名2) values (值1, 值2), (值1, 值2);
-- 批量添加数据(全部字段)
insert into 表名 values (值1, 值2, ...), (值1, 值2, ...);
- 例子
-- ============== 1. 指定字段添加单条数据 ==============
-- 只插入核心业务字段(id自增无需手动赋值)
INSERT INTO tb_student (student_id, name, gender, age, enrollment_date) VALUES ('20240001', '张三', '1', 18, '2024-09-01');
-- ============== 2. 全部字段添加单条数据 ==============
-- 全字段插入需按表字段顺序赋值,id为NULL时数据库自动自增
INSERT INTO tb_student VALUES (NULL, '20240002', '李四', '2', 19, '2024-09-01', NOW(), NOW());
-- ============== 3. 批量添加数据(指定字段) ==============
-- 批量插入3条,仅指定核心字段
INSERT INTO tb_student (student_id, name, gender, age, enrollment_date)
VALUES
('20240003', '王五', '0', 17, '2024-09-01'),
('20240004', '赵六', '1', 18, '2024-09-01'),
('20240005', '孙七', '2', 20, '2024-09-01');
-- ============== 4. 批量添加数据(全部字段) ==============
-- 批量插入4条,全字段赋值(id填NULL)
INSERT INTO tb_student
VALUES
(NULL, '20240006', '周八', '0', 18, '2023-09-01', NOW(), NOW()),
(NULL, '20240007', '吴九', '1', 19, '2023-09-01', NOW(), NOW()),
(NULL, '20240008', '赵十', '2', 17, '2025-09-01', NOW(), NOW()),
(NULL, '20240009', '钱十一', '0', 20, '2025-09-01', NOW(), NOW()),
(NULL, '20240010', '林十二', '1', 18, '2025-09-01', NOW(), NOW());
2.2.2 update 修改数据
- 语法
-- 修改数据
update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , .... [ where 条件 ] ;
- 例子
-- 注意:修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据,一般会加上 where 条件。
update tb_student set name = '竹之却', age=20 where id=1;
2.2.3 delete 删除数据
- 语法
-- 删除数据
delete from 表名 [where 条件];
- 例子
-- 删除 id 为1的这一条数据
delete from tb_student where id=1;
-- 删除全部数据,即清空表数据(慎用)
-- 自增主键不会重置,即主键 id 不会随着数据的清空而重置,当再插入一条数据时,id 会接着上一个 id 继续增加。
-- delete from tb_student;
-- 注意:清空整个数据表(谨慎使用,不可恢复,自增主键会重置)
-- TRUNCATE TABLE tb_student;
- 注意
DELETE 语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据。
DELETE 语句不能删除某一个字段的值(如果要操作,可以使用UPDATE,将该字段的值置为NULL)。
2.3 DQL
- 语法
```sql
select
字段列表
from
表名列表
</p></li>
</ol>
<hr />
<p>where
条件列表
<hr />
group by
分组字段列表
having
分组后条件列表
<hr />
order by
排序字段列表
<hr />
limit
分页参数
```
2.3.1 基本查询(select...from...)
- 语法
-- 查询多个字段
select 字段1,字段2,字段3 from 表名;
-- 查询所有字段(*号 为通配符,代表查询所有字段,在实际开发中尽量少用(不直观、影响效率)
select * from 表名;
-- 为查询字段设置别名,as关键字可以省略, 如果取别名建议加上 as关键字
select 字段1 [as 别名1], 字段2 [as 别名2] from 表名;
-- 去除重复记录 distinct
select distinct 字段列表 from 表名;
- 例子
-- 1. 查询多个字段(查询学号、姓名、性别、入学时间)
select student_id, name, gender, enrollment_date from tb_student;
-- 2. 查询所有字段(演示用,实际开发尽量避免使用*)
select * from tb_student;
-- 3. 为查询字段设置别名(as关键字保留,更规范)
select
student_id as 学号,
name as 姓名,
gender as 性别,
age as 年龄,
enrollment_date as 入学时间
from tb_student;
-- 别名含特殊字符(如空格)时,需用反引号/单引号/双引号包裹
select
student_id as `学生学号`,
name as `学生姓名`,
update_time as `最后更新时间`
from tb_student;
-- 4. 去除重复记录(distinct)
-- 示例1:查询所有不重复的性别(去重性别值)
select distinct gender from tb_student;
-- 示例2:查询不重复的入学时间+性别组合(多字段去重)
select distinct enrollment_date, gender from tb_student;
-- 示例3:去重+别名结合使用
select distinct gender as 性别类型 from tb_student;
2.3.2 条件查询(where)
- 语法
-- 条件查询
select 字段列表 from 表名 where 条件列表 ;
- 条件列表
比较运算符
功能
>
大于
>=
大于等于
<
小于
<=
小于等于
=
等于
<> 或 !=
不等于
between ... and ...
在某个范围之内(含最小、最大值)
in(...)
在in之后的列表中的值,多选一
like 占位符
模糊匹配(_匹配单个字符, %匹配任意个字符)
is null
是null
逻辑运算符
功能
and 或 &&
并且 (多个条件同时成立)
or 或 ||
或者 (多个条件任意一个成立)
not 或 !
非 , 不是
-
例子
-- 1. 查询所有男生的姓名和年龄(= 等于)
select name, age from tb_student where age=18;
-- 2. 查询年龄在 16 到 20 岁之间的学生(BETWEEN ... AND ... 范围)
select name, age from tb_student where age between 16 and 20;
-- 3. 查询学号为 20240001、20240002、20240003 的学生(IN(...) 多选一)
select * from tb_student where student_id in ('20240001', '20240002', '20240003');
-- 4. 查询所有 “赵” 姓,并且姓名为两个字的学生(LIKE _模糊匹配)
select * from tb_student where name like '赵_';
-- 5. 查询所有姓名中包含 “十” 字的学生(LIKE %模糊匹配)
select * from tb_student where name like '%十%';
-- 6. 查询年龄大于 18 岁且性别为男的学生(AND 逻辑与)
select * from tb_student where age>18 and gender='2';
2.3.3 分组查询(group by [, having])
- 语法
-- 分组查询
select 字段列表 from 表名 [where 条件列表] group by 分组字段名 [having 分组后过滤条件];
- 聚合函数
将一列数据作为一个整体,进行纵向计算。
注意:
- null值不参与所有聚合函数的运算 。
-
统计数量可以使用:count(),count(字段),count(常量);推荐使用count() 。
函数
功能
count
统计数量
max
最大值
min
最小值
avg
平均值
sum
求和
-
例子
-- 1. 按性别分组,统计每种性别的学生人数
select gender, count(*) as 人数(人) from tb_student group by gender;
-- 2. 按性别分组,计算每组的平均年龄(过滤年龄为空的记录)
select gender, avg(age) as 平均年龄 from tb_student where age is not null group by gender;
-- 3. 按入学年份分组,统计每年入学的学生总数
select year(enrollment_date) as enrollment_year, count(*) as total_students from tb_student group by year(enrollment_date);
-- 4. 按性别分组,筛选出平均年龄大于18岁的性别组
select gender, avg(age) as avg_age from tb_student where age is not null group by gender having avg(age) > 18;
-- 5. 按性别分组,统计每组人数,并只显示人数大于3的组
select gender, count(*) as student_count from tb_student group by gender having count(*) > 3;
- 注意事项
-
where与having的区别:
- 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
-
判断条件不同:where不能对聚合函数进行判断,而having可以。
-
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
-
执行顺序: where > 聚合函数 > having 。
2.3.4 排序查询(order by)
-
语法
-- 排序查询
select 字段列表 from 表名 [where 条件列表] [group by 分组字段名 having 分组后过滤条件] order by 排序字段 排序方式;
排序方式:升序(asc),降序(desc);默认为升序asc,asc可以不写。
如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序。
- 例子
-- 1. 按年龄升序(不写,默认asc)排序,年龄相同则按学号升序(显示书写asc)排序
select * from tb_student order by age, student_id asc;
-- 2. 按入学日期降序(desc)排序,只显示姓名和入学日期
select name, enrollment_date from tb_student order by enrollment_date desc;
2.3.5 分页查询(limit)
- 语法
-- 排序查询
select 字段 from 表名 [where 条件] [group by 分组字段 having 过滤条件] [order by 排序字段] limit 起始索引,每页展示记录数;
- 说明
起始索引从0开始 。
分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT 。
如果起始索引为0,起始索引可以省略,直接简写为 limit 10 。
起始索引计算公式:(页码-1)* 每页展示记录数
-
例子
-- 1. 查询第1页数据(每页3条)
select * from tb_student limit 0, 3;
-- 或简写为:limit 3;
select * from tb_student limit 3;
-- 2. 查询第2页数据(每页3条)
-- 建议配合排序,保证分页结果稳定
select * from tb_student order by id limit 3, 3;
三、多表设计
四、多表查询
五、事物

