一、基础概念
数据库: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° 日期类型
| 类型 | 大小(byte) | 范围 | 格式 | 描述 |
|---|---|---|---|---|
| date | 3 | 1000-01-01 至 9999-12-31 | YYYY-MM-DD | 日期值,包括 (年-月-日) |
| datetime | 8 | 1000-01-01 00:00:00 至 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值,包括 (年-月-日 时:分:秒) |
比如:
“`sql
— 生日只需要 年-月-日, 则使用 date
bithday date
— 创建时间和最后一个更新时间需要精确到 时:分:秒,则使用datetime
create_time datetime
update_time datetime
“`
- 约束介绍:
| 约束 | 描述 | 关键字 |
|---|---|---|
| 非空约束 | 限制该字段值不能为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 | 最后更新时间,非空,默认值为:当前系统时间 |
“`sql
— 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
(1)语法
select
字段列表
from
表名列表
----------------
where
条件列表
----------------
group by
分组字段列表
having
分组后条件列表
----------------
order by
排序字段列表
----------------
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)
(1)语法
-- 条件查询
select 字段列表 from 表名 where 条件列表 ;
(2)条件列表
| 比较运算符 | 功能 |
|---|---|
| > | 大于 |
| >= | 大于等于 |
| < | 小于 |
| <= | 小于等于 |
| = | 等于 |
| <> 或 != | 不等于 |
| between … and … | 在某个范围之内(含最小、最大值) |
| in(…) | 在in之后的列表中的值,多选一 |
| like 占位符 | 模糊匹配(_匹配单个字符, %匹配任意个字符) |
| is null | 是null |
| 逻辑运算符 | 功能 |
|---|---|
| and 或 && | 并且 (多个条件同时成立) |
| or 或 || | 或者 (多个条件任意一个成立) |
| not 或 ! | 非 , 不是 |
(3)例子
-- 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])
(1)语法
-- 分组查询
select 字段列表 from 表名 [where 条件列表] group by 分组字段名 [having 分组后过滤条件];
(2)聚合函数
- 聚合函数:将一列数据作为一个整体,进行纵向计算。
| 函数 | 功能 |
|---|---|
| count | 统计数量 |
| max | 最大值 |
| min | 最小值 |
| avg | 平均值 |
| sum | 求和 |
- 注意:
1° null值不参与所有聚合函数的运算 。
2° 统计数量可以使用:count(),count(字段),count(常量);推荐使用count() 。
(3)例子
-- 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;
(4)注意事项:
- where与having的区别:
- 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
-
判断条件不同:where不能对聚合函数进行判断,而having可以。
-
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
-
执行顺序: where > 聚合函数 > having 。
2.3.4 排序查询(order by)
(1)语法
-- 排序查询
select 字段列表 from 表名 [where 条件列表] [group by 分组字段名 having 分组后过滤条件] order by 排序字段 排序方式;
- 排序方式:升序(asc),降序(desc);默认为升序asc,asc可以不写。
- 如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序。
(2)例子
-- 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)
(1)语法
-- 排序查询
select 字段 from 表名 [where 条件] [group by 分组字段 having 过滤条件] [order by 排序字段] limit 起始索引,每页展示记录数;
(2)说明
- 起始索引从0开始 。
-
分页查询是数据库的方言,不同的数据库有不同的实现,MySQL中是LIMIT 。
-
如果起始索引为0,起始索引可以省略,直接简写为 limit 10 。
-
起始索引计算公式:(页码-1)* 每页展示记录数
(3)例子
-- 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;
