[数据库] 数据库基础与 MySQL 常用 SQL

163 0
Honkers 2026-6-23 22:57:17 来自手机 | 显示全部楼层 |阅读模式

第一章.数据库基础

1.1 数据库的介绍

  1. 1.数据库:
  2. 用来按照一定结构存储、管理和查询数据的软件系统。
  3. 2.常见关系型数据库:
  4. MySQL
  5. Oracle
  6. SQL Server
  7. PostgreSQL
  8. 3.关系型数据库:
  9. 使用表存储数据,表和表之间可以建立关系。
复制代码

1.2 数据库表

  1. 1.表 table:
  2. 数据库中存放数据的基本单位。
  3. 2.表由以下部分构成:
  4. a.表名
  5. b.列名,也叫字段名
  6. c.每列的数据类型
  7. d.行,也叫记录
复制代码
idusernamepassword
1tom111
2jack222

1.3 表和 Java 类的对应关系

数据库Java
表名类名
列名属性名
列类型属性类型
一行数据一个 JavaBean 对象
单元格数据对象的属性值
  1. public class User {
  2. private Integer id;
  3. private String username;
  4. private String password;
  5. }
复制代码
  1. // 表中的两行数据可以理解成两个对象:
  2. User user1 = new User(1, "tom", "111");
  3. User user2 = new User(2, "jack", "222");
复制代码

1.4 查询结果如何返回给 Java

  1. 1.数据库执行 SELECT 查询。
  2. 2.查询结果是一张临时结果表。
  3. 3.Java 程序逐行读取结果。
  4. 4.每一行封装成一个 JavaBean 对象。
  5. 5.多个对象放入 List 集合。
  6. 6.最终返回给页面或接口使用。
复制代码
  1. List<User> users = new ArrayList<>();
  2. users.add(new User(1, "tom", "111"));
  3. users.add(new User(2, "jack", "222"));
复制代码

第二章.SQL 语言

2.1 SQL 的介绍

  1. 1.SQL:
  2. Structured Query Language,结构化查询语言。
  3. 2.作用:
  4. 用来操作关系型数据库。
  5. 3.注意:
  6. 不同数据库都遵守 SQL 标准,
  7. 但也会有自己的语法差异,这些差异叫 SQL 方言。
复制代码

2.2 SQL 分类

分类全称作用常见关键字
DDLData Definition Language定义数据库对象CREATE、ALTER、DROP
DMLData Manipulation Language操作表中数据INSERT、UPDATE、DELETE
DQLData Query Language查询表中数据SELECT、FROM、WHERE
DCLData Control Language权限控制GRANT、REVOKE
TCLTransaction Control Language事务控制COMMIT、ROLLBACK

2.3 SQL 通用语法

  1. -- 1.SQL 可以单行或多行书写,通常以分号结尾。
  2. SELECT * FROM user;
  3. -- 2.MySQL 关键字不区分大小写,但建议关键字大写。
  4. SELECT username, password FROM user;
  5. -- 3.单行注释
  6. # 这是 MySQL 注释
  7. -- 这也是 SQL 注释
  8. -- 4.多行注释
  9. /*
  10. 这是多行注释
  11. */
复制代码
  1. 1.库名、表名、字段名可以使用反引号包裹。
  2. 2.字符串和日期值通常使用单引号。
  3. 3.SQL 中判断相等使用 =,不是 Java 中的 ==。
复制代码

2.4 MySQL 常用数据类型

类型说明示例
INT整数age INT
BIGINT大整数id BIGINT
DOUBLE双精度小数score DOUBLE
DECIMAL(m, d)精确小数,适合金额price DECIMAL(10,2)
CHAR(n)固定长度字符串gender CHAR(1)
VARCHAR(n)可变长度字符串name VARCHAR(20)
TEXT长文本content TEXT
DATE年月日2026-06-22
DATETIME年月日时分秒2026-06-22 10:30:00
TIMESTAMP时间戳常用于创建时间、修改时间

金额不要用 DOUBLE

金额、余额、价格等精确小数,优先使用 DECIMAL,不要使用 DOUBLE,避免精度误差。


第三章.DDL 数据定义语言

3.1 数据库操作

  1. -- 查看所有数据库
  2. SHOW DATABASES;
  3. -- 创建数据库
  4. CREATE DATABASE java_study;
  5. -- 如果不存在才创建
  6. CREATE DATABASE IF NOT EXISTS java_study;
  7. -- 使用数据库
  8. USE java_study;
  9. -- 查看当前正在使用的数据库
  10. SELECT DATABASE();
  11. -- 删除数据库
  12. DROP DATABASE java_study;
  13. -- 如果存在才删除
  14. DROP DATABASE IF EXISTS java_study;
复制代码

3.2 创建表

  1. CREATE TABLE user (
  2. id INT PRIMARY KEY AUTO_INCREMENT,
  3. username VARCHAR(20) NOT NULL,
  4. password VARCHAR(32) NOT NULL,
  5. age INT,
  6. create_time DATETIME
  7. );
复制代码
  1. 1.CREATE TABLE:
  2. 创建表。
  3. 2.字段格式:
  4. 字段名 数据类型 约束。
  5. 3.AUTO_INCREMENT:
  6. 自增长,通常配合整数主键使用。
复制代码

3.3 查看表结构

  1. -- 查看当前库中的所有表
  2. SHOW TABLES;
  3. -- 查看建表语句
  4. SHOW CREATE TABLE user;
  5. -- 查看表字段结构
  6. DESC user;
复制代码

3.4 修改表结构

  1. -- 添加字段
  2. ALTER TABLE user ADD email VARCHAR(50);
  3. -- 修改字段类型
  4. ALTER TABLE user MODIFY email VARCHAR(100);
  5. -- 修改字段名和类型
  6. ALTER TABLE user CHANGE email user_email VARCHAR(100);
  7. -- 删除字段
  8. ALTER TABLE user DROP user_email;
  9. -- 修改表名
  10. ALTER TABLE user RENAME TO sys_user;
复制代码

3.5 删除表

  1. -- 删除表
  2. DROP TABLE sys_user;
  3. -- 如果表存在才删除
  4. DROP TABLE IF EXISTS sys_user;
复制代码

第四章.DML 数据操作语言

4.1 插入数据

  1. -- 指定字段插入
  2. INSERT INTO product (pid, pname, price)
  3. VALUES (1, '苹果', 6.50);
  4. -- 不指定字段时,值必须覆盖所有列并保持顺序
  5. INSERT INTO product
  6. VALUES (2, '梨', 5.00, '水果');
  7. -- 一次插入多条数据
  8. INSERT INTO product (pid, pname, price)
  9. VALUES
  10. (3, '香蕉', 4.50),
  11. (4, '西瓜', 20.00),
  12. (5, '草莓', 18.80);
复制代码

字符串使用单引号

SQL 中字符串建议使用单引号。Java 拼接 SQL 时,双引号会和 Java 字符串本身冲突。

4.2 修改数据

  1. -- 修改指定商品价格
  2. UPDATE product
  3. SET price = 7.00
  4. WHERE pid = 1;
  5. -- 同时修改多个字段
  6. UPDATE product
  7. SET price = 8.00, category_name = '新鲜水果'
  8. WHERE pname = '苹果';
复制代码

UPDATE 一定注意 WHERE

如果不写 WHERE,会修改整张表的所有记录。

4.3 删除数据

  1. -- 删除指定数据
  2. DELETE FROM product
  3. WHERE pid = 1;
  4. -- 删除价格大于 100 的商品
  5. DELETE FROM product
  6. WHERE price > 100;
  7. -- 删除整张表数据
  8. DELETE FROM product;
复制代码

4.4 DELETE、TRUNCATE、DROP 区别

语句作用是否删除表结构是否可加 WHERE
DELETE删除表中数据可以
TRUNCATE TABLE清空整张表数据不可以
DROP TABLE删除整张表不可以
  1. TRUNCATE TABLE product;
  2. DROP TABLE product;
复制代码

第五章.约束

本章目标

约束用于限制字段数据,保证数据合法、唯一、非空以及多表之间的引用关系正确。

5.1 主键约束

  1. 1.关键字:
  2. PRIMARY KEY
  3. 2.特点:
  4. a.一张表通常应该有一个主键
  5. b.主键用于唯一标识一行数据
  6. c.主键不能重复
  7. d.主键不能为 NULL
复制代码

创建表时指定主键

  1. CREATE TABLE category (
  2. cid INT PRIMARY KEY,
  3. cname VARCHAR(20)
  4. );
复制代码

约束区域指定主键

  1. CREATE TABLE category (
  2. cid INT,
  3. cname VARCHAR(20),
  4. PRIMARY KEY (cid)
  5. );
复制代码

修改表添加主键

  1. CREATE TABLE category (
  2. cid INT,
  3. cname VARCHAR(20)
  4. );
  5. ALTER TABLE category ADD PRIMARY KEY (cid);
复制代码

5.2 联合主键

  1. 1.联合主键:
  2. 多个字段合起来作为一个主键。
  3. 2.特点:
  4. 多个字段的组合不能重复,并且主键字段不能为 NULL。
复制代码
  1. CREATE TABLE student_course (
  2. student_id INT,
  3. course_id INT,
  4. score INT,
  5. PRIMARY KEY (student_id, course_id)
  6. );
复制代码

5.3 删除主键

  1. ALTER TABLE student_course DROP PRIMARY KEY;
复制代码

5.4 自增长约束

  1. 1.关键字:
  2. AUTO_INCREMENT
  3. 2.特点:
  4. a.通常配合整数主键使用
  5. b.插入数据时主键可以不写
  6. c.MySQL 自动生成下一个编号
复制代码
  1. CREATE TABLE student (
  2. sid INT PRIMARY KEY AUTO_INCREMENT,
  3. sname VARCHAR(20)
  4. );
  5. INSERT INTO student (sname) VALUES ('tom');
  6. INSERT INTO student (sname) VALUES ('jack');
复制代码

5.5 非空约束

  1. 1.关键字:
  2. NOT NULL
  3. 2.特点:
  4. 被约束字段不能插入 NULL。
  5. 3.注意:
  6. NULL、空字符串 ''、字符串 'null' 不是一回事。
复制代码
  1. CREATE TABLE student (
  2. sid INT PRIMARY KEY AUTO_INCREMENT,
  3. sname VARCHAR(20) NOT NULL,
  4. score INT
  5. );
  6. INSERT INTO student (sname, score) VALUES ('tom', 100);
  7. INSERT INTO student (sname, score) VALUES ('', 99);
  8. INSERT INTO student (sname, score) VALUES ('null', 97);
复制代码

5.6 唯一约束

  1. 1.关键字:
  2. UNIQUE
  3. 2.特点:
  4. 被唯一约束修饰的字段不能重复。
  5. 3.和主键区别:
  6. a.一张表只能有一个主键,但可以有多个唯一约束
  7. b.主键不能为 NULL
  8. c.唯一约束在 MySQL 中可以有多个 NULL
复制代码
  1. CREATE TABLE role (
  2. rid INT PRIMARY KEY AUTO_INCREMENT,
  3. rname VARCHAR(20) UNIQUE
  4. );
  5. INSERT INTO role (rname) VALUES ('护士');
  6. INSERT INTO role (rname) VALUES ('教师');
复制代码

5.7 默认值约束

  1. 1.关键字:
  2. DEFAULT
  3. 2.作用:
  4. 插入数据时如果不指定该字段,自动使用默认值。
复制代码
  1. CREATE TABLE account (
  2. id INT PRIMARY KEY AUTO_INCREMENT,
  3. username VARCHAR(20) NOT NULL,
  4. status INT DEFAULT 1
  5. );
  6. INSERT INTO account (username) VALUES ('tom');
复制代码

5.8 外键约束

  1. 1.关键字:
  2. FOREIGN KEY
  3. 2.作用:
  4. 让从表字段引用主表主键,保证多表之间的数据关系正确。
  5. 3.常见关系:
  6. 分类表是主表。
  7. 商品表是从表。
  8. 商品表中的 category_id 引用分类表的 cid。
复制代码
  1. CREATE TABLE category (
  2. cid INT PRIMARY KEY AUTO_INCREMENT,
  3. cname VARCHAR(20) NOT NULL
  4. );
  5. CREATE TABLE product (
  6. pid INT PRIMARY KEY AUTO_INCREMENT,
  7. pname VARCHAR(30) NOT NULL,
  8. price DECIMAL(10, 2),
  9. category_id INT,
  10. CONSTRAINT fk_product_category
  11. FOREIGN KEY (category_id)
  12. REFERENCES category (cid)
  13. );
复制代码

第六章.DQL 基础查询

6.1 准备案例表

  1. CREATE TABLE product (
  2. pid INT PRIMARY KEY AUTO_INCREMENT,
  3. pname VARCHAR(30) NOT NULL,
  4. price DECIMAL(10, 2),
  5. category_name VARCHAR(20),
  6. stock INT,
  7. create_time DATETIME
  8. );
  9. INSERT INTO product (pname, price, category_name, stock, create_time)
  10. VALUES
  11. ('苹果', 6.50, '水果', 100, '2026-06-01 10:00:00'),
  12. ('香蕉', 4.50, '水果', 80, '2026-06-02 10:00:00'),
  13. ('牙刷', 9.90, '日用品', 200, '2026-06-03 10:00:00'),
  14. ('洗面奶', 59.00, '化妆品', 50, '2026-06-04 10:00:00'),
  15. ('电视', 2999.00, '家电', 10, '2026-06-05 10:00:00');
复制代码

6.2 中间遗漏补齐:从建库到查询的完整练习

练习目标

这一段把原笔记中间容易断开的内容串起来:先建库建表,再插入、修改、删除,最后做基础查询。

  1. -- 1.创建并使用数据库
  2. CREATE DATABASE IF NOT EXISTS db_java_basic;
  3. USE db_java_basic;
  4. -- 2.创建商品分类表
  5. CREATE TABLE category (
  6. cid INT PRIMARY KEY AUTO_INCREMENT,
  7. cname VARCHAR(20) NOT NULL UNIQUE
  8. );
  9. -- 3.创建商品表
  10. CREATE TABLE product (
  11. pid INT PRIMARY KEY AUTO_INCREMENT,
  12. pname VARCHAR(30) NOT NULL,
  13. price DECIMAL(10, 2),
  14. stock INT DEFAULT 0,
  15. category_id INT,
  16. create_time DATETIME,
  17. CONSTRAINT fk_product_category
  18. FOREIGN KEY (category_id)
  19. REFERENCES category (cid)
  20. );
  21. -- 4.插入分类数据
  22. INSERT INTO category (cname)
  23. VALUES ('水果'), ('化妆品'), ('家电');
  24. -- 5.插入商品数据
  25. INSERT INTO product (pname, price, stock, category_id, create_time)
  26. VALUES
  27. ('苹果', 6.50, 100, 1, '2026-06-01 10:00:00'),
  28. ('香蕉', 4.50, 80, 1, '2026-06-02 10:00:00'),
  29. ('洗面奶', 59.00, 50, 2, '2026-06-03 10:00:00'),
  30. ('电视', 2999.00, 10, 3, '2026-06-04 10:00:00');
  31. -- 6.修改商品库存
  32. UPDATE product
  33. SET stock = stock - 1
  34. WHERE pname = '苹果';
  35. -- 7.删除库存为 0 的商品
  36. DELETE FROM product
  37. WHERE stock = 0;
  38. -- 8.查询商品和分类
  39. SELECT p.pid, p.pname, p.price, p.stock, c.cname
  40. FROM product p
  41. JOIN category c ON p.category_id = c.cid
  42. ORDER BY p.price DESC;
复制代码
  1. 这段练习覆盖:
  2. 1.创建数据库。
  3. 2.创建主表和从表。
  4. 3.主键、自增长、非空、唯一、默认值、外键。
  5. 4.INSERT、UPDATE、DELETE。
  6. 5.JOIN 多表查询。
复制代码

6.3 简单查询

  1. -- 查询所有列
  2. SELECT * FROM product;
  3. -- 查询指定列
  4. SELECT pid, pname, price FROM product;
  5. -- 去重查询
  6. SELECT DISTINCT category_name FROM product;
  7. -- 计算查询
  8. SELECT pname, price + 100 AS new_price FROM product;
  9. -- 给表取别名
  10. SELECT p.pname, p.price FROM product AS p;
复制代码
  1. 1.SELECT 查询出来的结果是一张临时结果表。
  2. 2.* 表示查询所有列,实际开发中更推荐明确写出需要的列。
  3. 3.AS 可以给列或表取别名,AS 可以省略。
复制代码

6.4 条件查询

  1. -- 查询价格大于 10 的商品
  2. SELECT * FROM product WHERE price > 10;
  3. -- 查询价格在 5 到 60 之间的商品,包含边界
  4. SELECT * FROM product WHERE price BETWEEN 5 AND 60;
  5. -- 查询分类是水果或家电的商品
  6. SELECT * FROM product WHERE category_name IN ('水果', '家电');
  7. -- 查询商品名中包含 面 的商品
  8. SELECT * FROM product WHERE pname LIKE '%面%';
  9. -- 查询库存不为空的商品
  10. SELECT * FROM product WHERE stock IS NOT NULL;
复制代码
运算符说明
=等于
!= 或 <>不等于
>、>=、<、<=比较大小
BETWEEN ... AND ...区间范围,含头含尾
IN (...)在指定集合中
LIKE模糊查询
IS NULL判断为空
IS NOT NULL判断不为空
AND并且
OR或者
NOT

6.5 LIKE 通配符

通配符说明示例
%任意 0 个或多个字符LIKE '张%'
_任意 1 个字符LIKE '_三'
  1. -- 查询姓张的人
  2. SELECT * FROM user WHERE username LIKE '张%';
  3. -- 查询名字中包含香的商品
  4. SELECT * FROM product WHERE pname LIKE '%香%';
  5. -- 查询第二个字是想的数据
  6. SELECT * FROM product WHERE pname LIKE '_想%';
  7. -- 查询商品名正好四个字的数据
  8. SELECT * FROM product WHERE pname LIKE '____';
复制代码

6.6 排序查询

  1. 1.关键字:
  2. ORDER BY
  3. 2.排序规则:
  4. ASC: 升序,默认。
  5. DESC: 降序。
  6. 3.执行顺序:
  7. 先查询,最后排序。
复制代码
  1. -- 按价格升序
  2. SELECT * FROM product ORDER BY price ASC;
  3. -- 按库存降序
  4. SELECT * FROM product ORDER BY stock DESC;
  5. -- 先按分类升序,同分类内按价格降序
  6. SELECT * FROM product
  7. ORDER BY category_name ASC, price DESC;
复制代码

6.7 聚合查询

函数说明
COUNT(*)统计行数
SUM(列名)求和
AVG(列名)求平均值
MAX(列名)求最大值
MIN(列名)求最小值
  1. -- 统计商品总数
  2. SELECT COUNT(*) FROM product;
  3. -- 统计库存总数
  4. SELECT SUM(stock) FROM product;
  5. -- 查询平均价格、最高价格、最低价格
  6. SELECT AVG(price), MAX(price), MIN(price) FROM product;
复制代码

COUNT 的常见写法

COUNT(*) 统计行数;COUNT(列名) 只统计该列不为 NULL 的行。

6.8 分组查询

  1. 1.关键字:
  2. GROUP BY
  3. 2.作用:
  4. 把相同字段值的数据合并为一组。
  5. 3.WHERE 和 HAVING 区别:
  6. WHERE 在分组前过滤。
  7. HAVING 在分组后过滤。
复制代码
  1. -- 按分类统计商品数量
  2. SELECT category_name, COUNT(*) AS total
  3. FROM product
  4. GROUP BY category_name;
  5. -- 按分类统计平均价格,只看平均价格大于 20 的分类
  6. SELECT category_name, AVG(price) AS avg_price
  7. FROM product
  8. GROUP BY category_name
  9. HAVING AVG(price) > 20;
  10. -- 先过滤库存大于 0 的商品,再按分类统计
  11. SELECT category_name, COUNT(*) AS total
  12. FROM product
  13. WHERE stock > 0
  14. GROUP BY category_name;
复制代码

6.9 分页查询

  1. 1.关键字:
  2. LIMIT
  3. 2.语法:
  4. SELECT * FROM 表名 LIMIT 起始索引, 每页条数;
  5. 3.起始索引:
  6. (当前页 - 1) * 每页条数
复制代码
  1. -- 第 1 页,每页 3 条
  2. SELECT * FROM product LIMIT 0, 3;
  3. -- 第 2 页,每页 3 条
  4. SELECT * FROM product LIMIT 3, 3;
  5. -- 第 3 页,每页 3 条
  6. SELECT * FROM product LIMIT 6, 3;
复制代码
  1. int currentPage = 2;
  2. int pageSize = 5;
  3. int startRow = (currentPage - 1) * pageSize;
  4. // 总页数 = 向上取整(总记录数 / 每页条数)
  5. int totalPage = (int) Math.ceil(totalSize * 1.0 / pageSize);
复制代码

6.10 SQL 编写顺序和执行顺序

  1. SELECT category_name, COUNT(*) AS total
  2. FROM product
  3. WHERE price > 5
  4. GROUP BY category_name
  5. HAVING COUNT(*) >= 1
  6. ORDER BY total DESC
  7. LIMIT 0, 5;
复制代码
阶段顺序
书写顺序SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY -> LIMIT
大致执行顺序FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

第七章.MySQL 常用函数

7.1 字符串函数

函数说明
CONCAT(str1, str2)拼接字符串
LENGTH(str)获取字节长度
CHAR_LENGTH(str)获取字符长度
LOWER(str)转小写
UPPER(str)转大写
SUBSTRING(str, start, len)截取字符串
TRIM(str)去除首尾空格
  1. SELECT CONCAT(pname, '-', category_name) AS info FROM product;
  2. SELECT CHAR_LENGTH('数据库') AS len;
  3. SELECT SUBSTRING('abcdef', 2, 3) AS result;
复制代码

7.2 数值函数

函数说明
ROUND(num, d)四舍五入
CEIL(num)向上取整
FLOOR(num)向下取整
ABS(num)绝对值
  1. SELECT ROUND(3.14159, 2);
  2. SELECT CEIL(10.1);
  3. SELECT FLOOR(10.9);
复制代码

7.3 日期函数

函数说明
NOW()当前日期时间
CURDATE()当前日期
CURTIME()当前时间
YEAR(date)获取年份
MONTH(date)获取月份
DAY(date)获取日期中的天
DATE_FORMAT(date, format)格式化日期
  1. SELECT NOW();
  2. SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
  3. SELECT * FROM product WHERE YEAR(create_time) = 2026;
复制代码

7.4 流程函数

  1. -- IF(条件, 成立结果, 不成立结果)
  2. SELECT pname, IF(stock > 0, '有货', '无货') AS stock_status
  3. FROM product;
  4. -- CASE WHEN
  5. SELECT
  6. pname,
  7. CASE
  8. WHEN price >= 1000 THEN '高价'
  9. WHEN price >= 100 THEN '中价'
  10. ELSE '低价'
  11. END AS price_level
  12. FROM product;
复制代码

第八章.数据库三范式

本章目标

范式用于指导表结构设计,核心目标是减少数据冗余、避免更新异常、让表之间职责更清晰。

8.1 第一范式:字段保持原子性

  1. 1.第一范式:
  2. 表中的每个字段都应该是不可再拆分的原子值。
  3. 2.不符合示例:
  4. address_phone = '北京市昌平区xxx小区 1501087xxxx'
  5. 3.符合示例:
  6. province
  7. city
  8. detail_address
  9. phone
复制代码

8.2 第二范式:每行能被唯一区分

  1. 1.第二范式:
  2. 在满足第一范式基础上,每行数据应该能被唯一标识。
  3. 2.常见做法:
  4. 给每张表设计主键。
  5. 3.目的:
  6. 避免无法准确定位某一行数据。
复制代码
  1. CREATE TABLE student (
  2. sid INT PRIMARY KEY AUTO_INCREMENT,
  3. sname VARCHAR(20) NOT NULL
  4. );
复制代码

8.3 第三范式:非主键字段不能相互依赖

  1. 1.第三范式:
  2. 在满足第二范式基础上,非主键字段不能依赖其他非主键字段。
  3. 2.不符合示例:
  4. 员工表中同时保存 department_name 和 department_manager。
  5. department_manager 依赖 department_name,不直接依赖员工主键。
  6. 3.解决:
  7. 拆分部门表,员工表只保存 department_id。
复制代码
  1. CREATE TABLE department (
  2. did INT PRIMARY KEY AUTO_INCREMENT,
  3. dname VARCHAR(20) NOT NULL,
  4. manager VARCHAR(20)
  5. );
  6. CREATE TABLE employee (
  7. eid INT PRIMARY KEY AUTO_INCREMENT,
  8. ename VARCHAR(20) NOT NULL,
  9. department_id INT
  10. );
复制代码

8.4 三范式总结

  1. 1.第一范式:
  2. 一列数据不要混多个含义。
  3. 2.第二范式:
  4. 每张表要能唯一定位一行数据。
  5. 3.第三范式:
  6. 一张表不要记录多张表的信息。
复制代码

范式不是越高越好

业务开发中通常先保证设计清晰、减少冗余;在性能要求很高的场景,也可能为了查询效率适当冗余字段。


第九章.多表关系与外键

9.1 一对一关系

  1. 1.一对一:
  2. 一条主表数据对应一条从表数据。
  3. 2.示例:
  4. 用户表 user
  5. 用户详情表 user_profile
  6. 3.建表方式:
  7. 在其中一张表保存另一张表的主键,并加唯一约束。
复制代码
  1. CREATE TABLE user (
  2. uid INT PRIMARY KEY AUTO_INCREMENT,
  3. username VARCHAR(20) NOT NULL
  4. );
  5. CREATE TABLE user_profile (
  6. id INT PRIMARY KEY AUTO_INCREMENT,
  7. uid INT UNIQUE,
  8. real_name VARCHAR(20),
  9. id_card VARCHAR(18),
  10. FOREIGN KEY (uid) REFERENCES user (uid)
  11. );
复制代码

9.2 一对多关系

  1. 1.一对多:
  2. 一个分类包含多个商品。
  3. 一个商品只属于一个分类。
  4. 2.主表:
  5. 一的一方,例如分类表。
  6. 3.从表:
  7. 多的一方,例如商品表。
  8. 4.外键位置:
  9. 外键建在从表中。
复制代码
  1. CREATE TABLE category (
  2. cid INT PRIMARY KEY AUTO_INCREMENT,
  3. cname VARCHAR(20) NOT NULL
  4. );
  5. CREATE TABLE product (
  6. pid INT PRIMARY KEY AUTO_INCREMENT,
  7. pname VARCHAR(30) NOT NULL,
  8. category_id INT,
  9. FOREIGN KEY (category_id) REFERENCES category (cid)
  10. );
复制代码

9.3 多对多关系

  1. 1.多对多:
  2. 一个学生可以选多门课程。
  3. 一门课程可以被多个学生选择。
  4. 2.建表方式:
  5. 创建中间表。
  6. 3.中间表:
  7. 保存两张主表的主键作为外键。
复制代码
  1. CREATE TABLE student (
  2. sid INT PRIMARY KEY AUTO_INCREMENT,
  3. sname VARCHAR(20) NOT NULL
  4. );
  5. CREATE TABLE course (
  6. cid INT PRIMARY KEY AUTO_INCREMENT,
  7. cname VARCHAR(20) NOT NULL
  8. );
  9. CREATE TABLE student_course (
  10. sid INT,
  11. cid INT,
  12. score INT,
  13. PRIMARY KEY (sid, cid),
  14. FOREIGN KEY (sid) REFERENCES student (sid),
  15. FOREIGN KEY (cid) REFERENCES course (cid)
  16. );
复制代码

9.4 外键删除和更新策略

  1. 1.RESTRICT:
  2. 如果从表有引用,禁止删除或更新主表数据。
  3. 2.CASCADE:
  4. 主表删除或更新时,从表跟着删除或更新。
  5. 3.SET NULL:
  6. 主表删除或更新时,从表外键设置为 NULL。
复制代码
  1. CREATE TABLE product (
  2. pid INT PRIMARY KEY AUTO_INCREMENT,
  3. pname VARCHAR(30) NOT NULL,
  4. category_id INT,
  5. CONSTRAINT fk_product_category
  6. FOREIGN KEY (category_id)
  7. REFERENCES category (cid)
  8. ON DELETE SET NULL
  9. ON UPDATE CASCADE
  10. );
复制代码

谨慎使用级联删除

ON DELETE CASCADE 会在删除主表数据时自动删除从表数据,真实业务中要先确认数据是否允许被连带删除。


第十章.多表查询

10.1 准备多表数据

  1. CREATE TABLE category (
  2. cid INT PRIMARY KEY AUTO_INCREMENT,
  3. cname VARCHAR(20) NOT NULL
  4. );
  5. CREATE TABLE product (
  6. pid INT PRIMARY KEY AUTO_INCREMENT,
  7. pname VARCHAR(30) NOT NULL,
  8. price DECIMAL(10, 2),
  9. category_id INT
  10. );
  11. INSERT INTO category (cname) VALUES ('水果'), ('化妆品'), ('家电');
  12. INSERT INTO product (pname, price, category_id)
  13. VALUES
  14. ('苹果', 6.50, 1),
  15. ('香蕉', 4.50, 1),
  16. ('洗面奶', 59.00, 2),
  17. ('电视', 2999.00, 3),
  18. ('未知商品', 10.00, NULL);
复制代码

10.2 交叉查询

  1. 1.语法:
  2. SELECT 列名 FROM 表A, 表B;
  3. 2.问题:
  4. 会产生笛卡尔积。
  5. 3.解决:
  6. 添加连接条件。
复制代码
  1. -- 会产生笛卡尔积
  2. SELECT * FROM category, product;
  3. -- 添加连接条件后,相当于隐式内连接
  4. SELECT *
  5. FROM category c, product p
  6. WHERE c.cid = p.category_id;
复制代码

10.3 内连接查询

  1. 1.内连接:
  2. 查询两张表中满足连接条件的数据。
  3. 2.隐式内连接:
  4. SELECT 列名 FROM 表A, 表B WHERE 连接条件;
  5. 3.显式内连接:
  6. SELECT 列名 FROM 表A JOIN 表B ON 连接条件;
复制代码
  1. -- 隐式内连接
  2. SELECT p.pid, p.pname, p.price, c.cname
  3. FROM product p, category c
  4. WHERE p.category_id = c.cid;
  5. -- 显式内连接
  6. SELECT p.pid, p.pname, p.price, c.cname
  7. FROM product p
  8. JOIN category c ON p.category_id = c.cid;
  9. -- 查询化妆品分类下的商品
  10. SELECT p.pid, p.pname, p.price, c.cname
  11. FROM product p
  12. JOIN category c ON p.category_id = c.cid
  13. WHERE c.cname = '化妆品';
复制代码

10.4 外连接查询

  1. 1.左外连接:
  2. 查询左表全部数据,以及右表满足条件的数据。
  3. 2.右外连接:
  4. 查询右表全部数据,以及左表满足条件的数据。
  5. 3.关键字:
  6. LEFT JOIN
  7. RIGHT JOIN
复制代码
  1. -- 查询所有商品,即使商品没有分类也显示
  2. SELECT p.pid, p.pname, c.cname
  3. FROM product p
  4. LEFT JOIN category c ON p.category_id = c.cid;
  5. -- 查询所有分类,即使分类下没有商品也显示
  6. SELECT c.cid, c.cname, p.pname
  7. FROM product p
  8. RIGHT JOIN category c ON p.category_id = c.cid;
复制代码

10.5 UNION 联合查询

  1. 1.UNION:
  2. 合并多条查询语句的结果,并去除重复数据。
  3. 2.UNION ALL:
  4. 合并结果,不去重。
  5. 3.注意:
  6. 多条 SELECT 的列数和列类型需要能对应。
复制代码
  1. -- 模拟全外连接:左外连接结果 UNION 右外连接结果
  2. SELECT c.cid, c.cname, p.pid, p.pname
  3. FROM category c
  4. LEFT JOIN product p ON c.cid = p.category_id
  5. UNION
  6. SELECT c.cid, c.cname, p.pid, p.pname
  7. FROM category c
  8. RIGHT JOIN product p ON c.cid = p.category_id;
复制代码

10.6 子查询

  1. 1.子查询:
  2. 一条 SELECT 语句作为另一条 SQL 的一部分。
  3. 2.常见位置:
  4. WHERE 后面作为条件。
  5. FROM 后面作为临时表。
复制代码

子查询作为条件

  1. -- 查询化妆品分类下的商品
  2. SELECT *
  3. FROM product
  4. WHERE category_id = (
  5. SELECT cid FROM category WHERE cname = '化妆品'
  6. );
  7. -- 查询化妆品和家电分类下的商品
  8. SELECT *
  9. FROM product
  10. WHERE category_id IN (
  11. SELECT cid FROM category WHERE cname IN ('化妆品', '家电')
  12. );
复制代码

子查询作为临时表

  1. -- 查询每个分类的商品数量,再筛选数量大于 1 的分类
  2. SELECT temp.category_id, temp.total
  3. FROM (
  4. SELECT category_id, COUNT(*) AS total
  5. FROM product
  6. GROUP BY category_id
  7. ) AS temp
  8. WHERE temp.total > 1;
复制代码

10.7 多表查询选择

需求推荐写法
只要两表匹配的数据内连接
保留左表全部数据左外连接
保留右表全部数据右外连接
查询条件来自另一条 SQL子查询
合并多个查询结果UNION 或 UNION ALL

第十一章.事务

本章目标

事务用于保证一组 SQL 操作要么全部成功,要么全部失败,常见于转账、下单、扣库存等场景。

11.1 事务的介绍

  1. 1.事务:
  2. 一组数据库操作组成的逻辑执行单元。
  3. 2.核心目标:
  4. 要么全部成功提交,要么全部失败回滚。
  5. 3.典型场景:
  6. 张三给李四转账 100 元。
  7. 张三扣 100 和李四加 100 必须同时成功。
复制代码

11.2 事务基本操作

  1. -- 开启事务
  2. START TRANSACTION;
  3. -- 张三扣款
  4. UPDATE account SET balance = balance - 100 WHERE name = '张三';
  5. -- 李四收款
  6. UPDATE account SET balance = balance + 100 WHERE name = '李四';
  7. -- 提交事务
  8. COMMIT;
复制代码
  1. -- 如果中途出现问题
  2. ROLLBACK;
复制代码

11.3 事务四大特性 ACID

特性说明
原子性 Atomicity一组操作不可拆分,要么都成功,要么都失败
一致性 Consistency事务前后数据状态必须合法
隔离性 Isolation多个事务并发执行时互不干扰到规定程度
持久性 Durability事务提交后数据永久保存

11.4 并发事务问题

问题说明
脏读一个事务读到另一个事务未提交的数据
不可重复读同一事务两次读取同一行,结果不同
幻读同一事务两次范围查询,行数不同

11.5 事务隔离级别

隔离级别脏读不可重复读幻读
READ UNCOMMITTED可能可能可能
READ COMMITTED避免可能可能
REPEATABLE READ避免避免可能
SERIALIZABLE避免避免避免
  1. -- 查看当前事务隔离级别
  2. SELECT @@transaction_isolation;
  3. -- 设置当前会话隔离级别
  4. SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
复制代码

MySQL 默认隔离级别

InnoDB 默认隔离级别通常是 REPEATABLE READ。


第十二章.索引

本章目标

索引用于提高查询效率,但会占用空间,也会影响新增、修改、删除速度。

12.1 索引的介绍

  1. 1.索引:
  2. 帮助数据库快速定位数据的数据结构。
  3. 2.优点:
  4. 提高查询速度。
  5. 3.缺点:
  6. a.占用磁盘空间
  7. b.新增、修改、删除时需要维护索引
复制代码

12.2 常见索引类型

类型说明
主键索引主键自动创建
唯一索引保证字段值唯一
普通索引只提高查询效率
联合索引多个字段组成一个索引
  1. -- 创建普通索引
  2. CREATE INDEX idx_product_name ON product (pname);
  3. -- 创建唯一索引
  4. CREATE UNIQUE INDEX idx_user_username ON user (username);
  5. -- 创建联合索引
  6. CREATE INDEX idx_product_category_price ON product (category_id, price);
  7. -- 删除索引
  8. DROP INDEX idx_product_name ON product;
复制代码

12.3 查看 SQL 是否使用索引

  1. EXPLAIN
  2. SELECT *
  3. FROM product
  4. WHERE pname = '苹果';
复制代码
  1. EXPLAIN 可以查看 SQL 的执行计划。
  2. 入门阶段重点关注:
  3. 1.type:
  4. 访问类型,一般越接近 const/ref/range 越好,ALL 表示全表扫描。
  5. 2.key:
  6. 实际使用的索引。
  7. 3.rows:
  8. 预计扫描行数。
复制代码

12.4 索引使用建议

  1. 适合加索引:
  2. 1.经常作为 WHERE 条件的字段。
  3. 2.经常用于 JOIN 连接的字段。
  4. 3.经常用于 ORDER BY、GROUP BY 的字段。
  5. 4.数据量较大的表。
  6. 不适合加索引:
  7. 1.数据量很小的表。
  8. 2.频繁更新但很少查询的字段。
  9. 3.区分度很低的字段,例如性别。
复制代码

12.5 最左前缀原则

  1. 1.联合索引:
  2. INDEX(a, b, c)
  3. 2.可以较好使用索引的条件:
  4. WHERE a = ?
  5. WHERE a = ? AND b = ?
  6. WHERE a = ? AND b = ? AND c = ?
  7. 3.不符合最左前缀:
  8. WHERE b = ?
  9. WHERE c = ?
复制代码
  1. CREATE INDEX idx_order_user_status_time
  2. ON orders (user_id, status, create_time);
  3. -- 符合最左前缀
  4. SELECT * FROM orders WHERE user_id = 1 AND status = 1;
  5. -- 不符合最左前缀
  6. SELECT * FROM orders WHERE status = 1;
复制代码

第十三章.视图

13.1 视图的介绍

  1. 1.视图:
  2. 基于 SELECT 查询结果创建的虚拟表。
  3. 2.特点:
  4. a.视图本身通常不直接保存数据
  5. b.可以简化复杂查询
  6. c.可以隐藏部分字段,控制数据暴露范围
复制代码

13.2 创建和使用视图

  1. CREATE VIEW v_product_category AS
  2. SELECT p.pid, p.pname, p.price, c.cname
  3. FROM product p
  4. JOIN category c ON p.category_id = c.cid;
  5. SELECT * FROM v_product_category;
复制代码

13.3 修改和删除视图

  1. -- 修改视图
  2. CREATE OR REPLACE VIEW v_product_category AS
  3. SELECT p.pid, p.pname, c.cname
  4. FROM product p
  5. JOIN category c ON p.category_id = c.cid;
  6. -- 删除视图
  7. DROP VIEW v_product_category;
复制代码

视图不是性能优化万能方案

视图主要用于封装查询和控制字段暴露,不等于一定能提升性能。复杂视图仍然需要关注底层 SQL 和索引。


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行