通用技术 mysql mysql知识点总结 coderxst 2023-07-08 2024-05-25 一.基础 1.1.终端连接数据库 1 2 3 4 5 # 方式一: mysql - uroot - pxxxxxx # 方式二: mysql - uroot - p Enter password: your password
1.2.SQL 语句分类
DDL(Data Definition Language):数据定义语言
可以通过 DDL 语句对数据库或者表进行:创建、删除、修改等操作
DML(Data Manipulation Language):数据操作语言
可以通过 DML 语句对表进行:添加、删除、修改等操作
DQL(Data Query Language):数据查询语言
DCL(Data Control Language):数据控制语言
1.3.数据库操作
MySQL 默认的数据库
infomation_schema
:信息数据库,其中包括 MySQL 在维护的其他数据库、表、列、访问 权限等信息
performance_schema
:性能数据库,记录着 MySQL Server 数据库引擎在运行过程中的一 些资源消耗相关的信息
mysql
:用于存储数据库管理者的用户信息、权限信息以及一些日志信息等
sys
:相当于是一个简易版的 performance_schema,将性能数据库中的数据汇总成更容易 理解的形式
数据库操作命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # 显示数据库 SHOW DATABASES;# 创建数据库 CREATE DATABASE test;CREATE DATABASE IF NOT EXISTS test;CREATE DATABASE IF NOT EXISTS testDEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;# 删除数据库 DROP DATABASE test;DROP DATABASE IF EXIT test;# 修改数据库的字符集和排序规则 ALTER DATABASE test CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;# 使用数据库 use test; # 查看当前正在使用的数据库 SELECT DATABASE();
1.4.数据表操作 1.4.1.数据类型 MySQL 支持的数据类型有:数字类型,日期和时间类型,字符串(字符和字节)类型,空间类型和 JSON 数据类型。
数字类型,参考(https://dev.mysql.com/doc/refman/8.0/en/integer-types.html )
整数数字类型:TINYINT(1B),SMALLINT(2B),MEDIUMINT(3B),INTEGER,INT(4B),BIGINT(8B)
浮点数字类型:FLOAT,DOUBLE(FLOAT 是 4 个字节,DOUBLE 是 8 个字节)
精确数字类型:DECIMAL,NUMERIC(DECIMAL 是 NUMERIC 的实现形式)
日期类型
字符串类型
CHAR
类型在创建表时为固定长度,长度可以是 0 到 255 之间的任何值
VARCHAR
类型的值是可变长度的字符串,长度可以指定为 0 到 65535 之间的值
BINARY
和VARBINARY
类型用于存储二进制字符串,存储的是字节字符串
BLOB
用于存储大的二进制类型
TEXT
用于存储大的字符串类型
1.4.2.表约束
主键:PRIMARY KEY
一张表中,为了区分每一条记录的唯一性,必须有一个字段是永远不会重复,并且不会为空的,这个字段通常会将它设置为主键
主键是表中唯一的索引
并且必须是NOT NULL
的,如果没有设置 NOT NULL
,那么 MySQL 也会隐式的设置为NOT NULL
主键也可以是多列索引,PRIMARY KEY(key_part, ...)
,一般称之为联合主键
建议:开发中主键字段应该是和业务无关的,尽量不要使用业务字段来作为主键
唯一:UNIQUE
某些字段在开发中希望是唯一的,不会重复的,比如手机号码、身份证号码等,这个字段可以使用UNIQUE
来约束
使用UNIQUE
约束的字段在表中必须是不同的
UNIQUE
索引允许NULL
包含的列具有多个值NULL
不能为空:NOT NULL
某些字段要求用户必须插入值,不可以为空,这个时候可以使用 NOT NULL
来约束
默认值:DEFAULT
某些字段希望在没有设置值时给予一个默认值,这个时候可以使用 DEFAULT
来完成
自动递增:AUTO_INCREMENT
某些字段希望不设置值时可以进行递增,比如用户的 id,这个时候可以使用AUTO_INCREMENT
来完成
外键约束也是最常用的一种约束手段,详见后续多表关系
1.4.3.数据表的操作
表结构的操作
1 2 3 4 5 6 7 8 9 10 11 # 创建一张表 CREATE TABLE IF NOT EXISTS `users`( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (20 ) NOT NULL , age INT DEFAULT 0 , telPhone VARCHAR (20 ) DEFAULT '' UNIQUE NOT NULL ); # 删除数据表 DROP TABLE users;DROP TABLE IF EXISTS users;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 1. 修改表名 ALTER TABLE `moments` RENAME TO `moment`;# 2. 添加一个新的列 ALTER TABLE `moment` ADD `publishTime` DATETIME;ALTER TABLE `moment` ADD `updateTime` DATETIME;# 3. 删除一列数据 ALTER TABLE `moment` DROP `updateTime`;# 4. 修改列的名称 ALTER TABLE `moment` CHANGE `publishTime` `publishDate` DATE ;# 5. 修改列的数据类型 ALTER TABLE `moment` MODIFY `id` INT ;
表数据记录的操作
1 2 3 4 5 6 7 8 # 创建一张新的表 CREATE TABLE IF NOT EXISTS `products`( `id` INT PRIMARY KEY AUTO_INCREMENT, `title` VARCHAR (20 ), `description` VARCHAR (200 ), `price` DOUBLE , `publishTime` DATETIME );
1 2 3 4 5 # 插入数据 INSERT INTO `products` (`title`, `description`, `price`, `publishTime`)VALUES ('iPhone' , 'iPhone12只要998' , 998.88 , '2023-06-01' );INSERT INTO `products` (`title`, `description`, `price`, `publishTime`)VALUES ('huawei' , 'iPhoneP40只要888' , 888.88 , '2023-06-01' );
1 2 3 4 5 6 7 # 删除数据 # 1. 删除表中所有的数据 DELETE FROM `products`;# 2. 删除符合条件的数据 DELETE FROM `products` WHERE `title` = 'iPhone' ;
1 2 3 4 5 6 7 # 修改数据 # 1. 修改表中所有的数据 UPDATE `products` SET `title` = 'iPhone12' , `price` = 1299.88 ;# 2. 会修改符合条件的数据 UPDATE `products` SET `title` = 'iPhone12' , `price` = 1299.88 WHERE `title` = 'iPhone' ;
1 2 3 # 修改表结构,在每次修改完数据后,直接可以显示最新的更新时间 ALTER TABLE `products` ADD `updateTime` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ;
1.5.DML 语句
DQL:Data Query Language(数据查询语言)
SELECT
用于从一个或者多个表中检索选中的行(Record)
查询格式
数据表结构
1 2 3 4 5 6 7 8 9 10 CREATE TABLE IF NOT EXISTS `products` ( id INT PRIMARY KEY AUTO_INCREMENT, brand VARCHAR (20 ), title VARCHAR (100 ) NOT NULL , price DOUBLE NOT NULL , score DECIMAL (2 ,1 ), voteCnt INT , url VARCHAR (100 ), pid INT );
基本查询
1 2 3 4 5 6 7 8 # 查询所有的数据并且显示所有的字段 SELECT * FROM `products`;# 查询title、brand、price SELECT title, brand, price FROM `products`;# 给字段起别名:别名一般在多张表或者给客户端返回对应的key时会使用到 SELECT title as t, brand as b, price as p FROM `products`;
WHERE 条件查询(比较运算符)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 查询价格小于1000 的手机 SELECT * FROM `products` WHERE price < 1000 ;# 查询价格大于等于2000 的手机 SELECT * FROM `products` WHERE price >= 2000 ;# 价格等于3399 的手机 SELECT * FROM `products` WHERE price = 3399 ;# 价格不等于3399 的手机 SELECT * FROM `products` WHERE price != 3399 ;# 查询华为品牌的手机 SELECT * FROM `products` WHERE `brand` = '华为' ;
WHERE 条件查询(逻辑运算符)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # 1. AND (&& ): 两个条件都满足 # 查询品牌是华为,并且小于2000 元的手机 SELECT * FROM `products` WHERE `brand` = '华为' AND `price` < 2000 ;SELECT * FROM `products` WHERE `brand` = '华为' && `price` < 2000 ;# 查询1000 到2000 的手机(不包含1000 和2000 ) SELECT * FROM `products` WHERE price > 1000 AND price < 2000 ;# 2. OR : 符合一个条件即可 # 查询所有的华为手机或者价格小于1000 的手机 SELECT * FROM `products` WHERE brand = '华为' OR price < 1000 ;# 3. BETWEEN AND : 在一个区间范围内 # 查询1000 到2000 的手机(包含1000 和2000 ) SELECT * FROM `products` WHERE price BETWEEN 1000 AND 2000 ;# 4. IN : 在一个列表中(数组) # 查看多个结果中的一个 SELECT * FROM `products` WHERE brand in ('华为' , '小米' );
WHERE 条件查询(模糊查询)
模糊查询使用LIKE
关键字,结合两个特殊的符号
%
表示匹配任意个的任意字符
_
表示匹配一个的任意字符
1 2 3 4 5 6 7 8 # 查询所有以v开头的title SELECT * FROM `products` WHERE title LIKE 'v%' ;# 查询带M的title SELECT * FROM `products` WHERE title LIKE '%M%' ;# 查询带M的title必须是第三个字符 SELECT * FROM `products` WHERE title LIKE '__M%' ;
查询结果排序
当查询到结果的时候,希望将结果按照某种方式进行排序,这个时候使用的是ORDER BY
RDER BY
有两个常用的值
1 SELECT * FROM `products` WHERE brand = '华为' OR price < 1000 ORDER BY price ASC ;
分页查询
数据库中的数据非常多时,一次性查询到所有的结果进行显示是不太现实的
在真实开发中,都会要求用户传入offset
、limit
或者page
等字段
目的是可以在数据库中进行分页查询
用法有[LIMIT {[offset,] row_count | row_count OFFSET offset}]
1 2 3 4 5 6 SELECT * FROM `products` LIMIT 30 OFFSET 0 ;SELECT * FROM `products` LIMIT 30 OFFSET 30 ;SELECT * FROM `products` LIMIT 30 OFFSET 60 ;# 另外一种写法:offset , row_count SELECT * FROM `products` LIMIT 90 , 30 ;
二.进阶
products 表结构,在本章节案例使用
1 2 3 4 5 6 7 8 9 10 CREATE TABLE IF NOT EXISTS `products` ( id INT PRIMARY KEY AUTO_INCREMENT, brand VARCHAR (20 ), title VARCHAR (100 ) NOT NULL , price DOUBLE NOT NULL , score DECIMAL (2 ,1 ), voteCnt INT , url VARCHAR (100 ), pid INT );
2.1.MySQL 聚合函数
聚合函数表示对值的集合进行操作的组(集合)函数
1 2 3 4 5 6 7 8 9 10 11 12 13 # 华为手机价格的平均值 SELECT AVG (price) FROM `products` WHERE brand = '华为' ;# 计算所有手机的平均分 SELECT AVG (score) FROM `products`;# 手机中最低和最高分数 SELECT MAX (score) FROM `products`;SELECT MIN (score) FROM `products`;# 计算总投票人数 SELECT SUM (voteCnt) FROM `products`;# 计算所有条目的数量 SELECT COUNT (* ) FROM `products`;# 华为手机的个数 SELECT COUNT (* ) FROM `products` WHERE brand = '华为' ;
Group By
事实上聚合函数相当于默认将所有的数据分成了一组
前面使用avg
还是max
等,都是将所有的结果看成一组来计算的
如果希望划分多个组:比如华为、苹果、小米等手机分别的平均价格,应该怎么来做呢?
这个时候可以使用 GROUP BY
GROUP BY
通常和聚合函数一起使用:表示先对数据进行分组,再对每一组数据,进行聚合函数的计算
1 2 3 4 5 6 7 8 9 10 11 12 # 需求 # 1. 根据品牌进行分组 # 2. 计算各个品牌中:商品的个数、平均价格 # 3. 也包括:最高价格、最低价格、平均评分 SELECT brand, COUNT (* ) as count, ROUND(AVG (price), 2 ) as avgPrice, MAX (price) as maxPrice, MIN (price) as minPrice, AVG (score) as avgScore FROM `products` GROUP BY brand;
Group By 的约束条件
如果希望给Group By
查询到的结果添加一些约束,那么可以使用:HAVING
。
1 2 3 4 5 6 7 8 9 # 希望筛选出平均价格在4000 以下,并且平均分在7 以上的品牌 SELECT brand, COUNT (* ) as count, ROUND(AVG (price), 2 ) as avgPrice, MAX (price) as maxPrice, MIN (price) as minPrice, AVG (score) as avgScore FROM `products` GROUP BY brandHAVING avgPrice < 4000 and avgScore > 7 ;
2.2.MySQL 的外键约束
假如在上面的商品表中,对应的品牌还需要包含其他的信息
如果直接在商品中去体现品牌相关的信息,会存在一些问题
一方面,products
表中应该表示的都是商品相关的数据,应该又另外一张表来表示brand
的数据
另一方面,多个商品使用的品牌是一致时,会存在大量的冗余数据
所以,可以将所有的品牌数据,单独放到一张表中,创建一张品牌的表
1 2 3 4 5 6 7 8 9 10 11 12 13 # 创建brand表 CREATE TABLE IF NOT EXISTS `brand`( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (20 ) NOT NULL , website VARCHAR (100 ), worldRank INT ); # 添加数据 INSERT INTO `brand` (name, website, worldRank) VALUES ('华为' , 'www.huawei.com' , 1 );INSERT INTO `brand` (name, website, worldRank) VALUES ('小米' , 'www.mi.com' , 10 );INSERT INTO `brand` (name, website, worldRank) VALUES ('苹果' , 'www.apple.com' , 5 );INSERT INTO `brand` (name, website, worldRank) VALUES ('oppo' , 'www.oppo.com' , 15 );
将两张表联系起来,可以将products
中的brand_id
关联到brand
中的id
1 2 3 4 5 6 # 如果是创建表添加外键约束,需要在创建表的()最后添加如下语句 FOREIGN KEY (brand_id) REFERENCES brand(id)# 如果是表已经创建好,额外添加外键 ALTER TABLE `products` ADD `brand_id` INT ;ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id);
将 products 中的 brand_id 关联到 brand 中的 id 的值
1 2 3 4 5 # 注意:在brans表中,华为的id为1 ,小米的id为2 ,苹果的id为3 ,oppo的id为4 UPDATE `products` SET `brand_id` = 1 WHERE `brand` = '华为' ;UPDATE `products` SET `brand_id` = 4 WHERE `brand` = 'OPPO' ;UPDATE `products` SET `brand_id` = 3 WHERE `brand` = '苹果' ;UPDATE `products` SET `brand_id` = 2 WHERE `brand` = '小米' ;
修改或者删除 brand 表的的 id,让 products 表中的 bread_id 同步更新
1 2 3 4 5 6 7 8 9 10 # 可以查看到创建表时的sql 语句,找到外键的名称,products_ibfk_1 SHOW CREATE TABLE `products`;# 删除外键约束 ALTER TABLE `products` DROP FOREIGN KEY products_ibfk_1;# 重新添加外键,并且设置在on delete 或者on update 的值为CASCADE,同步更新 ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id)ON UPDATE CASCADEON DELETE CASCADE
2.3.MySQL 的多表查询
默认多表查询的结果
1 SELECT * FROM `products`, `brand`
假如第一张表有 108 条数据, 第二张表有 6 条数据,那么一共查询到的数据记录个数为 108 * 6
第一张表中每一个条数据,都会和第二张表中的每一条数据结合一次
这个结果称之为笛卡尔乘积,也称之为直积,表示为 X*Y
where 条件查询
表示查询到笛卡尔乘积后的结果中,符合products.brand_id
= brand.id
条件的数据过滤出来
如果有的在products
表中,但在brand
表中没有与之相关联的数据,那么那些数据也无法展示出来
1 2 SELECT * FROM `products`, `brand` WHERE `products`.brand_id = `brand`.id;
2.4.表和表间的连接方式
事实上想要的效果并不是上述那样的,而且表中的某些特定的数据,这个时候可以使用 SQL JOIN
操作,连接方式有以下四种。
左连接
如果希望获取到的是左边所有的数据(以左表为主)
这个时候就表示无论左边的表是否有对应的brand_id
的值对应右边表的id
,左边的数据都会被查询出来
这个也是开发中使用最多 的情况,它的完整写法是LEFT [OUTER] JOIN
,但是OUTER
可以省略的
1 2 3 4 5 6 7 8 SELECT * FROM `products`LEFT JOIN `brand`ON `products`.brand_id = `brand`.id;SELECT * FROM `products` LEFT JOIN `brand`ON `products`.brand_id = `brand`.idWHERE brand.id IS NULL ;
右连接
如果希望获取到的是右边所有的数据(以由表为主):
这个时候就表示无论左边的表中的brand_id
是否有和右边表中的id
对应,右边的数据都会被查询出来
右连接在开发中没有左连接常用,它的完整写法是RIGHT [OUTER] JOIN
,但是OUTER
可以省略的
1 2 3 4 5 6 7 8 SELECT * FROM `products`RIGHT JOIN `brand`ON `products`.brand_id = `brand`.id;SELECT * FROM `products`RIGHT JOIN `brand`ON `products`.brand_id = `brand`.idWHERE products.id IS NULL
内连接
事实上内连接是表示左边的表和右边的表都有对应的数据关联
内连接在开发中偶尔也会有一些场景使用,看自己的场景
内连接有其他的写法:CROSS JOIN
或者 JOIN
都可以
1 2 3 SELECT * FROM `products`INNER JOIN `brand`ON `products`.brand_id = `brand`.id;
1 2 SELECT * FROM `products`, `brand`WHERE `products`.brand_id = `brand`.id
会发现他们不同写法实现的效果是一样的
但是他们代表的含义并不相同
SQL 语句一:内连接,代表的是在两张表连接时就会约束数据之间的关系,来决定之后查询的结果
SQL 语句二:where
条件,代表的是先计算出笛卡尔乘积,在笛卡尔乘积的数据基础之上进行 where 条件的帅选
全连接
SQL 规范中全连接是使用FULL JOIN
,但是MySQL
中并没有对它的支持,我们需要使用 UNION
来实现
1 2 3 4 5 6 7 8 9 10 11 ( SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id ) UNION ( SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id );
1 2 3 4 5 6 7 8 9 10 11 12 13 ( SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id WHERE `brand`.id IS NULL ) UNION ( SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id WHERE `products`.id IS NULL );
2.5.多对多数据查询语句
多对多的关系的案例
比如学生可以选择多门课程,一个课程可以被多个学生选择
建立两张表
1 2 3 4 5 6 7 8 9 10 11 12 13 # 创建学生表 CREATE TABLE IF NOT EXISTS `students`( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (20 ) NOT NULL , age INT ); # 创建课程表 CREATE TABLE IF NOT EXISTS `courses`( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR (20 ) NOT NULL , price DOUBLE NOT NULL );
1 2 3 4 5 6 7 8 9 10 11 12 # 插入students表数据 INSERT INTO `students` (name, age) VALUES ('jack' , 18 );INSERT INTO `students` (name, age) VALUES ('tom' , 22 );INSERT INTO `students` (name, age) VALUES ('lilei' , 25 );INSERT INTO `students` (name, age) VALUES ('lucy' , 16 );INSERT INTO `students` (name, age) VALUES ('lily' , 20 );# 插入courses表数据 INSERT INTO `courses` (name, price) VALUES ('英语' , 100 );INSERT INTO `courses` (name, price) VALUES ('语文' , 666 );INSERT INTO `courses` (name, price) VALUES ('数学' , 888 );INSERT INTO `courses` (name, price) VALUES ('历史' , 80 );
创建关系表
1 2 3 4 5 6 7 8 # 创建关系表 CREATE TABLE IF NOT EXISTS `students_select_courses`( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL , course_id INT NOT NULL , FOREIGN KEY (student_id) REFERENCES students(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (course_id) REFERENCES courses(id) ON UPDATE CASCADE ON DELETE CASCADE );
1 2 3 4 5 6 7 8 # jack选修了 英文和数学 INSERT INTO `students_select_courses` (student_id, course_id) VALUES (1 , 1 );INSERT INTO `students_select_courses` (student_id, course_id) VALUES (1 , 3 );# lilei选修了 语文和数学和历史 INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3 , 2 );INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3 , 3 );INSERT INTO `students_select_courses` (student_id, course_id) VALUES (3 , 4 );
查询多对多数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 查询所有的选课学生选择的所有课程 SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuJOIN `students_select_courses` ssc ON stu.id = ssc.student_id JOIN `courses` cs ON ssc.course_id = cs.id; # 查询所有的学生选课情况(包括没有选课的学生) SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuLEFT JOIN `students_select_courses` ssc ON stu.id = ssc.student_id LEFT JOIN `courses` cs ON ssc.course_id = cs.id;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # jack同学选择了哪些课程 SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuJOIN `students_select_courses` ssc ON stu.id = ssc.student_id JOIN `courses` cs ON ssc.course_id = cs.id WHERE stu.id = 1 ;# lily同学选择了哪些课程(注意,这里必须用左连接,事实上上面也应该使用的是左连接) SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuLEFT JOIN `students_select_courses` ssc ON stu.id = ssc.student_id LEFT JOIN `courses` cs ON ssc.course_id = cs.id WHERE stu.id = 5 ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # 哪些学生是没有选课的 SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuLEFT JOIN `students_select_courses` ssc ON stu.id = ssc.student_id LEFT JOIN `courses` cs ON ssc.course_id = cs.id WHERE cs.id IS NULL ;# 查询哪些课程没有被学生选择 SELECT stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price coursePrice FROM `students` stuRIGHT JOIN `students_select_courses` ssc ON stu.id = ssc.student_id RIGHT JOIN `courses` cs ON ssc.course_id = cs.id WHERE stu.id IS NULL ;