mysql基础教程

1.初识MySQL

JavaEE:企业级Java开发 Web

前端(页面:展示,数据!)

后端(连接点:连接数据库JDBC,链接前端(控制,控制视图跳转,和给前端传递数据))

数据库(存数据,txt,Excel,word)

只会写代码,学好数据库,基本混饭吃!

操作系统,数据结构与算法!当一个不错的程序猿!

离散数学,数字电路,体系结构,编译原理。+实战经验,高级程序员~优秀的程序猿

1.1 为什么学习数据库?

1、岗位需求

2、现在的世界,大数据时代~,得数据库者得天下。

3、被迫需求: 存数据

4、数据库是所有软件体系中最核心的存在 DBA

1.2 什么是数据库?

数据库(DB,DataBase)

概念:数据仓库,软件,安装在操作系统(windows、linux、mac…)之上!SQL,可以存储大量的数据。500万!

作用:存储数据,管理数据

1.3 数据分类

关系型数据库:SQL

  • MySQL,Oracle,Sql Server,DB2,SQLlite
  • 通过表和表之间,行和列之间的关系进行数据的存储,如:学员表和考勤表之间的关联

非关系型数据库:NoSQL(Not Only)

  • Redis,MongDB
  • 非关系型数据库,对象存储,通过对象的自身的属性来决定。

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据。维护和获取数据;
  • MySQL,数据管理系统(Database Management System)

1.4 MySQL简介

MySQL是一个关系型数据库管理系统

  • 前世: 瑞典MySQL AB 公司

  • 今生: 属于 Oracle 旗下产品

  • MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。

  • 开源的数据库软件~

  • 体积小、速度快、总体拥有成本低。招人成本比较低,所有人必须会~

  • 中小型网站、或者大型网站,集群!

官网:https://www.mysql.com

现在用的最多的5.7,比较稳定,8.0最新版

1.5 安装MySQL

安装教程https://blog.csdn.net/weixin_45277249/article/details/114202833

1.6 连接数据库

打开MySQL命令窗口

  • 在DOS命令行窗口进入 安装目录\mysql\bin
  • 可设置环境变量,设置了环境变量,可以在任意目录打开!

连接数据库语句 : mysql -h 服务器主机地址 -u 用户名 -p 用户密码

注意 : -p后面不能加空格,否则会被当做密码的内容,导致登录失败 !本机操作可省略-h参数

查看MySQL版本信息和用户名:select version(),user();

version()返回MySQL版本号,user()返回连接数据库的用户名

几个基本的数据库操作命令 :

  • 展示所有数据库

    show databases;
    
  • 切换到某个数据库

    use 数据库名;
    
  • 查看数据库下所有表

    show tables;
    
  • 退出mysql

    exit;
    
  • 刷新数据库

    flush privileges;
    
  • 显示表mysql数据库中user表的列信息

    describe user;
    
  • 修改密码

    update user set password=password('123456')where user='root';
    
MySQL 数据库服务器的组成
  • 以数据库为基本单位 : 系统数据库 用户数据库

  • 以数据表 (table) 为基本单位

SQL(Structed Query language) 结构化查询语言
  • DML数据操作语言(Data Manipulation Language):用来操作数据库中所包含的数据

    • 如:INSERT、UPDATE、DELETE
  • DDL数据定义语言(Data definition Language) :用于创建和删除数据库对象等操作

    • 如:CREATE、DROP、ALTER
  • DQL数据查询语言(Data Query Language) :用来对数据库中的数据进行查询

    • 如:SELECT
  • DCL数据控制语言(Data Control Language):用来控制数据库组件的存取许可、存取权限等

    • 如:GRANT、COMMIT、ROLLBACK

2.操作数据库

2.1 操作数据库

带了 [ ] 就是可选的

  • 创建数据库

    create database [if not exists] 数据库名;-- if not exists意思是如果不存在则创建
    
  • 查看数据库列表

    show databases;-- 该列表中会有四个系统数据库和自己建的数据库
    
  • 使用数据库

    use `school`;-- 如果你的表名或字段名是一个特殊字符,就需要带反引号
    
  • 删除数据库

    drop database [if exists] 数据库名;
    

注意:以分号作为一条命令的结束符,Windows系统下默认不区分大小写

2.2 数据类型

数值

类型 说明 取值范围 存储需求
TINYINT 非常小的数据 有符值: -27 ~ 27-1 无符号值:0 ~ 28-1 1字节
SMALLINT 较小的数据 有符值: -215 ~ 215-1 无符号值: 0 ~ 216-1 2字节
MEDIUMINT 中等大小的数据 有符值: -223 ~ 223-1 无符号值: 0 ~ 224-1 3字节
INT 标准整数 有符值: -231 ~ 231-1 无符号值:0 ~ 232-1 4字节
BIGINT 较大的整数 有符值: -263 ~263-1 无符号值:0 ~264-1 8字节
FLOAT 单精度浮点数 ±1.1754351e -38 4字节
DOUBLE -> java double 双精度浮点数 ±2.2250738585072014e -308 8字节
DECIMAL 字符串形式的浮点数 Decimal(M,D) M+2个字节

字符串

字符串类型 说明 长度
CHAR[(M)] 定长字符串 M字节
VARCHAR[(M)] 可变字符串 可变长度
TINYTEXT 微型文本串 0~28–1字节
TEXT 文本串 0~216–1字节

VARCHAR相对于Java的String

日期类型

日期类型 格式 取值范围
DATE YYYY-MM-DD,日期格式 1000-01-01~ 9999-12-31 年月日
DATETIME YY-MM-DD hh:mm:ss: 1000-01-01 00:00:00 ~9999-12-31 23:59:59 年月日时分秒
TIME hh:mm:ss: -835:59:59 ~ 838:59:59
TIMESTAMP YYYYMMDDHHMMSS 1970年某时刻~2038年某时刻,精度为1秒
YEAR YYYY格式的年份 1901~2155

null

  • 没有值,未知

【注意】不要使用NULL进行运算,结果为NULL

2.3 数据库的字段属性

  • UNSIGNED:设置该列不可出现负数

  • ZEROFILL: 不足位数 0 填充 ,设定向这属性该列自动会有 UNSIGEND

  • UNIQUE KEY(UK): 唯一约束,设置字段的值是唯一的 允许为空,但只能有一个空值

  • PRIMARY KEY(PK):设置主键,就是能够唯一标识某个数据表数据的列,只要设置为主键 该列必须是非空 且唯一

  • FOREIGN KEY(FK) :用于在两表之间建立关系,需要指定引用主表的哪一字段

  • auto_increment:自动增长,在上一条记录的基础上+1(默认),可以自定义主键自增的起始值和步长

  • NOT NULL: 标识该列不许为空

  • DEFAULT :设置默认值

  • COMMENT :给列或表加注释

2.4 操作数据表

  • 创建数据表

    CREATE TABLE [IF NOT EXISTS] `表名`(
    	`字段名` 列类型 [属性] [索引] [注释],
    	`字段名` 列类型 [属性] [索引] [注释],
    	……
    	`字段名` 列类型 [属性] [索引] [注释],
    )[表类型] [字符集设置] [注释]
    
    create table [IF NOT EXISTS] `user`(
    	id INT PRIMARY KEY AUTO_INCREMENT COMMENT '编号',
    	username VARCHAR(25) not null COMMENT '姓名',
    	gender VARCHAR(2) DEFAULT '男' not NULL
    )COMMENT '用户表';
    

    【注意】使用英文括号,表名和字段名尽量使用反引号括起来

  • 删除数据表

    drop TABLE [IF EXISTS] `表名`;
    
  • 常用命令

    SHOW CREATE DATABASE `user` -- 查看创建数据库的语句
    SHOW CREATE TABLE `user` -- 查看student数据表的定义语句
    -- 显示表的结构
    DESC `user` 
    DESCRIBE `uer`
    

2.5 数据库引擎

  • INNODB 默认使用~
  • MYISAM 早些年使用的
名称 InnoDB MyISAM
事务处理 支持 不支持
数据行锁定 支持 不支持
外键约束 支持 不支持
全文索引 不支持 支持
表空间大小 较大,约MyISAM的2倍 较小

适用场合

  • 使用MyISAM: 不需事务,空间小,以查询访问为主
  • 使用InnoDB: 多删除、更新操作,安全性高,事务处理及并发控制

在物理空间存在的位置

  • 所有的数据库文件都存在data目录下
  • 本质还是文件的存储!

MySQL引擎在物理文件上的区别

  • InnoDB 在数据库表中只有一个*.frm文件,以及上级目录下的 ibdata1文件
  • MYISAM 对应文件
    • *.frm 表结构的定义文件
    • *.MYD 数据文件(data)
    • *.MYI 索引文件(index)

设置数据库表的字符集编码

CHARSET=utf8

不设置的话,会是mysql默认的字符集编码~(不支持中文!)

MySQL的默认编码是Latin1,不支持中文

在my.ini中配置默认的编码

character-set-server=utf8

2.6 修改和删除表

  • 修改表名

    ALTER TABLE `旧名` rename `新名`;
    
  • 添加字段

    ALTER TABLE `表名` ADD 字段名 列属性;
    
  • 修改表的字段

    ALTER TABLE `表名` MODIFY 字段名 列属性;-- 修改约束,不改名,重新设定
    ALTER TABLE `表名` CHANGE 旧字段名 新字段名 列属性;-- 字段重命名
    
  • 删除表的字段

    ALTER TABLE `表名` drop `字段名`
    
  • 删除数据表

    drop TABLE [IF EXISTS] `表名`;
    

所有的创建和删除操作尽量加上判断,以免报错~

【注意点】

  • 使用``把字段名或表名包起来
  • 单行注释 : – 注释内容 #注释内容 多行注释: /* 注释内容 */
  • sql关键字大小写不 敏感,建议大家写小写
  • 所有的符号全部用英文

3.MySQL数据管理

mysql运算符

类型 符号
算术运算符 + 加 -减 *乘 / 除 %取余
赋值运算符 =
比较/关系运算符 = 判断相等 > 大于 <小于 >=大于等于 <=小于等于 <> 或 != 不等于
逻辑运算符 and并且(&&) or或者(||) not非(取反)
between 某个区间,between 2 and 5(2 - 5之间)

3.1 外键(了解即可)

外键:一张表里的某个字段引用着另一张表里的某个字段信息.(==外键可以保证数据的合理性和完整一致性)

【注意】

  • 外键因为其强制约束,导致我们在对表操作时,时刻需要考虑到外键,增加了复杂性
  • 往往在大型项目中,会取消物理外键,而改用逻辑外键
  • 删除有外键关系的表,必须要先删除引用的别的表(从表),再删除被引用的表(主表)
设置外键
ALTER TABLE student
	ADD CONSTRAINT fk_student_grade
		FOREIGN KEY (gradeid)
			REFERENCES grade(id);
删除外键
ALTER TABLE student drop FOREIGN KEY fk_student_grade

以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰)

最佳实践

  • 数据库就是单纯的表,只用来存数据,只有 行(数据) 和 列(字段)
  • 我们想使用多张表的数据,想使用外键(程序去实现)

3.2 DML语言(全部记住)

数据库意义:数据存储,数据管理

  • insert
  • update
  • delete

添加

  • 语法

    INSERT INTO 表名 列名 VALUES 值列表
    
  • 插入一条数据

    INSERT INTO student(studentNo,studentName`password`,gradeid,sex,phone,address,borthday,email,card)
    VALUES
    (null,'小明','123123',1,'男','123123123','北京','2001-1-1','[email protected]','9999999');
    
  • 插入多条数据

    -- id设置了自增,可以省略不写
    insert into grade (id,gradeName)
    VALUES('s1'),('s2'),('y2');
    

【注意】

  • 如果你没有指定要给哪些字段赋值,那么必须按照数据库表的字段依次赋值
  • 字段是可以省略的,但是后面的值要一一对应

修改

语法

update 表名 SET 列名 = 更新值 [WHERE 更新条件]
  • 修改一个字段

    update `student` SET `name`='小明' WHERE id=1;
    
  • 修改多个字段

    update `student` SET `name`='小明',age=17 WHERE id=1;
    
  • 多个条件

    update `student` SET `name`='小明' WHERE id=1 AND age=1
    
  • 修改一个区间的数据

    update `student` SET `name`='小明' WHERE id<5
    

【注意】

  • 不指定条件的情况下,会改动所有这个列的数据
  • 更新值可以是一个具体的值,也可以是一个变量
  • 修改多个属性,中间使用英文逗号隔开

删除

delete命令
  • 语法

    DELETE FROM 表名 [WHERE 删除条件]
    
  • 删除指定数据

    delete from `student` WHERE id =1
    
TRUNCATE命令

作用:完全清空一个数据库表,表的结构和索引约束不会变!

-- TRUNCATE TABLE 表名
TRUNCATE TABLE `student`
DELETE和TRUNCATE的区别:
  • 相同点,都能删除数据,都不会删除表结构
  • truncate会重新设置自增列,计数器会归零
  • truncate不会影响事务

了解即可:delete删除的问题,重启数据库,现象

  • InnoDB:自增列会从1开始(存在内存当中的,断电即失)
  • MyISAM:继续从上一个自增量开始(存在文件中的,不会丢失)

4.DQL查询数据(最重点)

Data Query Language:数据查询语言

  • 所有查询操作都能用它,Select
  • 简单的查询,复杂的查询都能做~
  • 数据库中最核心的语言,最重要的语句
  • 使用频率最高的语句
查询所有数据
select * from `表名`;-- *代表全部列
查询指定字段
select `字段1`,`字段2`,`字段n` from `表名`;-- 语法
------------------------------------------------
select `name`,`age` from `student`;
起别名
  • 起别名使用AS关键字,可以给字段起别名,也可以给表起别名
  • 有的时候,列名不是那么的见名知意,那么我们就起别名,字段名 AS 别名
select `字段1` AS 别名1,`字段2` AS 别名2 from `表名` AS别名; -- 语法
-----------------------------------------------------------------
select `name` AS 姓名,`age` AS 年龄 from `student` AS s;
CONCAT 函数
  • 查出来的name前面都会加上==姓名:==
select CONCAT('姓名:',name) from student;
distinct 去重
  • 发现重复数据,去重
select distinct `StudentNo` from `student`;
数据库的列(表达式)
  • 数据库中的表达式:文本值,列,null,函数,计算表达式,系统变量……
  • select 表达式 from 表名
SELECT VERSION()  -- 查询mysql版本(函数)
SELECT 100*3-1 AS 计算结果 -- 用来计算(表达式)
SELECT @@auto_increment_increment -- 查询自增的步长(变量)
--------------------------------------------------------
-- 学员考试成绩 +1分查看
SELECT StudentNo,StudentResult + 1 AS '提分后' FROM result
WEHER条件子句
  • 检索数据中符合条件的值
运算符 语法 描述
and && a and b a&&b 并且,两个都为真,结果为真
or || a or b a||b 或,其中一个为真,结果为真
not ! not a !a 逻辑非,真为假,假为真!
-- 查询考试成绩在95-100分之间
SELECT studentNo,StudentResult FROM result
WHERE StudentResult>=95 AND StudentResult<=100

-- 模糊查询(区间)
SELECT studentNo,StudentResult FROM result
WHERE StudentResult BETWEEN 95 AND 100

-- 除了1000号学生之外的成绩
SELECT studentNo,StudentResult FROM result
WHERE NOT studentNo = 1000
模糊查询
运算符 语法 描述
IS NULL a is null 如果操作符为NULL,结果为真
IS NOT NULL a is not null 如果操作符不为NULL,结果为真
BERWEEN a between b and c 若a在b和c之间,则结果为真
LIKE a like b SQL匹配,如果a匹配b,则结果为真
IN a in (a1,a2,a3……) 假设a在a1或者a2……其中的某一个值中,结果为真
==============LIKE模糊查询====================

-- 查询姓刘的同学  %代表任意字符
SELECT StudentNo,StudentName FROM student
WHERE StudentName LIKE '刘%'

-- 查询姓刘的同学,名字后面只有一个字符
SELECT StudentNo,StudentName FROM student
WHERE StudentName LIKE '刘_'

-- 查询名字中间有 “明”的同学
SELECT StudentNo,StudentName FROM student
WHERE StudentName LIKE '%明%'

=========in(具体的一个或多个值)==============

-- 查询 1001,1002,1003号学员
SELECT StudentNo,StudentName FROM student
WHERE StudentNo IN(1001,1002,1003)

-- 查询在北京的学生
SELECT StudentNo,StudentName FROM student
WHERE address IN(北京)

=============null   not null=================

-- 查询地址为空的学生 null  ''
SELECT StudentNo,StudentName FROM student
WHERE address='' OR address IS NULL

-- 查询有出生日期的同学  不为空
SELECT StudentNo,StudentName FROM student
WHERE birndate IS NOT NULL

4.高级查询

完整的查询语法

select [select选项] 字段列表[字段别名] from 数据源 
[where 字句] [group by子句 ] [having 子句]  [order by 子句] [limit 子句]; 

参考文章https://blog.csdn.net/u011991249/article/details/64519945

4.1 联表查询 join

mysql基础教程_第1张图片

==================INNER JOIN======================

-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
SELECT * FROM student
SELECT * FROM result

/*
思路
1.分析需求,分析查询的字段来自哪些表(连接查询)
2.确定使用哪种连接查询?七种
确定交叉点(两个表中哪个数据是相同的)
判断的条件:学生表中的 studentNo = 成绩表中的 studentNo
*/

-- join(连接的表) on(判断的条件)  连接查询
-- where等值查询

SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM stdent AS s
INNER JOIN result AS r
WHERE s.studentNo=r.studentNo

-- Right JOIN
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM stdent s
RIGHT JOIN result r
ON s.studentNo=r.studentNo

-- Left JOIN
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM stdent s
LEFT JOIN result r
ON s.studentNo=r.studentNo

-- 查询缺考的同学
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM stdent s
LEFT JOIN result r
ON s.studentNo=r.studentNo
WHERE StudentResult IS NULL

-- 查询参加了考试的同学信息:学号,学生姓名,科目名,分数
/*
思路
1.分析需求,分析查询的字段来自哪些表,studnet、result、subject(连接查询)
2.确定使用哪种连接查询?七种
确定交叉点(两个表中哪个数据是相同的)
判断的条件:学生表中的 studentNo = 成绩表中的 studentNo
*/
SELECT s.studentNo,studentName,SubjectNo,StudentResult
FROM stdent s
RIGHT JOIN result r
ON s.studentNo=r.studentNo
INNER JOIN `subject` sub
ON r.studentNo=sub.SubjectNo
操作 描述
Inner join 如果表中至少有一个匹配,就返回行
left join 会从左表中返回所有的值,即使右表中没有匹配
right join 会从右表中返回所有的值,即使左表中没有匹配
a LEFT JOIN b -- 在左边就是左表
  • 我要查询哪些数据 SELECT ……
  • 从哪些表中查 FROM 表 xxx join 连接的表 on 交叉条件
  • 假设存在一种多张表查询,慢慢来,先查询两张表,再慢慢增加

4.2 自连接

自连接是内连接的一种,内连接可分为等值连接和自身连接。

等值连接:查找两个表中连接字段相等的记录。

自身连接: 就是和自己进行连接查询,给一张表取两个不同的别名,然后附上连接条件。

  • 自连接是同一个表不同实例的连接操作
  • 自连接必须指定别名(aliasName)区分不同实例

现在我们有一张category表

  • pid为1的是父栏目,其他都是子栏目
  • 子栏目的pid对应的是父栏目的categoryid
categoryid pid categoryName
2 1 信息技术
3 1 软件开发
4 3 数据库
5 1 美术设计
6 3 web开发
7 2 办公信息
8 5 ps技术

我们把上表拆分成两张表来看

  • 父栏目
categoryid categoryName
2 信息技术
3 软件开发
5 美术设计
  • 子栏目
pid categoryName
3 数据库
2 办公信息
3 web开发
5 美术设计

操作:查询父类对应的子类

-- 把一张表看成两张一模一样的表
SELECT a.categoryName AS '父栏目',b.categoryName AS '子栏目'
FROM category AS a,category AS b
WHERE a.categoryid = b.pid

结果如下:

父栏目 子栏目
信息技术 办公信息
软件开发 数据库
软件开发 web开发
美术设计 ps技术

下面这个例子来自https://www.zhihu.com/question/290782386

以下面这张表为例:

mysql基础教程_第2张图片

要查询与姓名 HH 同龄且籍贯也相同的学生信息。就可以用自连接查询:

SELECT B.学号, B.姓名, B.性别, B.籍贯, B.年龄 
FROM student A  
JOIN student B 
ON A.年龄=B.年龄 AND A.籍贯=B.籍贯 AND A.姓名='HH'

结果如下:

img

4.3 分页和排序

排序
  • 排序使用ORDER BY ,后面跟的字段就是以它排序
  • 降序desc 由大到小
  • 升序asc 由小到大
select * from result ORDER BY StudentResult asc; -- 升序

select * from result ORDER BY StudentResult desc;-- 降序
分页

为什么要分页?假设你有100万条数据

  • 缓解数据库压力
  • 给人的体验更好
LIMIT 起始值,pageSize
-- 起始值是从第几条数据开始
-- pageSize是页面大小,也就是每页显示多少条数据
  • 起始值 = (当前页-1)*页面大小

  • 数据总数 / 页面大小 = 总页数

-- 第一页
select * from `subject` LIMIT 0,5; -- (1-1)*5
-- 第二页
select * from `subject` LIMIT 5,5; -- (2-1)*5
-- 第三页
select * from `subject` LIMIT 10,5; -- (3-1)*5
-- 第n页
select * from `subject` LIMIT (n-1)*5,pageSize; -- (n-1)*pageSize,pageSize

4.4 子查询

where (这个值是计算出来的)

本质:在where语句中嵌套一个子查询语句

where(select *from)

  • 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),降序排列
-- 方式一:使用连接查询
SELECT `studentNo`,`SubjectName`,`StudentResult`
FROM `result` r
INNER JOIN `subject`sub
ON r.SubjectNo = sub.SubjectNo
WHERE SubjectName = '数据库结构-1'
ORDER BY StudentResult DESC

-- 方式二:使用子查询()
SELECT `studentNo`,`SubjectName`,`StudentResult`
FROM `result`
WHERE SubjectNo = (
	-- 查询所有 数据库结构-1 的学生学号
	SELECT SubjectNo FROM `subject` WHERE SubjectName = '数据库结构-1'
)
ORDER BY StudentResult DESC
  • 分数不小于80分的学生的学号和姓名
SELECT s.`StudentNo`,`SudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE `StudentResult` >= 80
  • 分数不小于80分的学生的学号和姓名,科目为高等数学-2
SELECT s.`StudentNo`,`SudentName`
FROM student s
INNER JOIN result r
ON r.StudentNo = s.StudentNo
WHERE `StudentResult` >= 80 AND `SubjectNo` = (
	SELECT SubjectNo FROM `subject` WHERE `SubjectName` = '高等数学-2'
)
  • 查询课程为 高等数学-2 且分数不小于 80 的同学的学号和姓名
-- 方式一:连接查询
SELECT s.`StudentNo`,`SudentName`
FROM student s
INNER JOIN result r
ON s.StudentNo = r.StudentNo
INNER JOIN `subject` sub
ON r.`SubjectNo` = sub.SubjectNo
WHERE `SubjectName`='高等数学-2' AND StudentResult>=80
-- 方式二:嵌套子查询
SELECT `StudentNo`,`SudentName` FROM student WHERE StudentNo IN(
	SELECT StudentNo FROM result WHERE StudentResult>80 AND SubjectNo=(
		SELECT SubjectNo FROM `subject` WHERE `SubjectName` = '高等数学-2'
	)
)

4.5 分组和过滤

-- 查询不同课程的平均分,最高分,最低分,平均分大于80
-- 根据不同课程分组(要点)

SELECT SubjectName,AVG(StudentResult) AS 平均分,Max(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result r
INNER JOIN `subject` sub
ON r.SubjectNo = sub.SubjectNo
GROUP BY r.SubjectNo -- 通过什么字段来分组
HAVING 平均分 > 80

5.mysql常用函数

官网地址:https://dev.mysql.com/doc/refman/5.7/en/sql-function-reference.html

5.1 常用函数

  • 数学运算

    SELECT ABS(-8) -- 绝对值
    SELECT CEILING(9.4) -- 向上取整
    SELECT FLOOR(9.4) -- 向下取整
    SELECT RAND() -- 返回一个0~1之间的随机数
    SELECT SIGN(-10) -- 判断一个数的符号 0返回0 负数返回-1 正数返回1
    
  • 字符串函数

    SELECT CHAR_LENGTH('即使再小的帆也能远航') -- 字符串长度
    SELECT CONCAT('你','好','mysql') -- 拼接字符串
    SELECT INSERT('我爱编程',1,2,'超级热爱') -- 查询,从某个位置开始替换某个长度
    SELECT LOWER('Chen') -- 小写字符
    SELECT UPPER('Chen') -- 大小字符
    SELECT INSTR('Chen','C') -- 返回第一次出现字符串的索引
    SELECT REPLACE('坚持就能成功','坚持','努力')-- 替换出现的指定字符
    SELECT SUBSTRING('坚持就能成功',5,6) -- 返回指定的子字符串
    SELECT REVERSE('害历好') -- 反转
    
  • 时间和日期

    SELECT CURRENT_DATE() -- 获取当前日期
    SELECT CURDATE() -- 获取当前日期
    SELECT NOW() -- 获取当前时间
    SELECT LOCALTIME() -- 本地时间
    SELECT SYSDATE() -- 系统时间
    
    SELECT YEAR(NOW()) -- 年
    SELECT MONTH(NOW()) -- 月
    SELECT DAY(NOW()) -- 日
    SELECT HOUR(NOW()) -- 时
    SELECT MINUTE(NOW()) -- 分
    SELECT SECOND(NOW()) -- 秒
    
  • 系统

    SELECT SYSTEM_USER() -- 系统当前用户
    SELECT USER() -- 系统当前用户
    SELECT VERSION() -- 当前版本
    

5.2 聚合函数(常用)

函数名称 描述
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
-- 都能够统计表中的数据(想查询一个表中有多少条记录,就使用count())
SELECT COUNT(studentname) FROM student; -- COUNT(字段),会忽略所有null值 
SELECT COUNT(*) FROM student; -- COUNT(*),不会忽略null值
SELECT COUNT(1) FROM result; -- COUNT(1),不会忽略null值

SELECT SUM(`StudentResult`) AS 总和 FROM result
SELECT AVG(`StudentResult`) AS 平均分 FROM result
SELECT MAX(`StudentResult`) AS 最高分 FROM result
SELECT MIN(`StudentResult`) AS 最低分 FROM result

6.事务

6.1 什么是事务?

事务(Transaction)是指将一系列数据操作捆绑成为一个整体进行统一管理。

  1. 如果某一事务执行成功,则在该事务中进行的所有数据更改均会提交,成为数据库的永久组成部分

  2. 如果事务执行时遇到错误且必须取消或回滚,则数据将全部恢复到操作前的状态,所有数据的更改均被消除

下面是一个转账操作


A有1000元,B有200元

1、SQL执行 A 给 B 转账200元

2、SQL执行 B 收到 A 的钱

最后 A有800元,B有400元


上面的转账操作,A的钱转出去了,而程序执行到这里出错,B没有收到钱,那钱不就丢了,这个时候事务的作用来了

  • 事务就是将一组sql语句放在同一批次内去执行
  • 要么全部执行成功 要么全部失败
  • 数据库引擎innodb(默认的 支持事务) mysiam

6.2 事务的ACID原则

原子性(Atomicity)

一个事务的所有系列操作步骤被看成一个动作,所有的步骤要么全部完成,要么一个也不会完成。

如果在事务过程中发生错误,则会回滚到事务开始前的状态,将要被改变的数据库记录不会被改变。

一致性(Consistency)

一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏,即数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性。

隔离性(Isolation)

主要用于实现并发控制,隔离能够确保并发执行的事务按顺序一个接一个地执行。

通过隔离,一个未完成事务不会影响另外一个未完成事务。

持久性(Durability)

一旦一个事务被提交,它应该持久保存,不会因为与其他操作冲突而取消这个事务。


隔离所导致的一些问题

脏读

指一个事务读取了另外一个事务未提交的数据。

不可重复读

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

虚读(幻读)

是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。(一般是行影响,多了一行)

6.3 执行事务

-- mysql 是默认开启的事务自动提交的
-- 关闭自动提交后,从下一条SQL语句开始则开启新事务,需使用COMMIT或ROLLBACK语句结束该事务
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认的)

-- 手动处理事务

-- 事务开启 或 BEGIN;
START TRANSACTION -- 标记一个事务的开始,从这个之后的 sql 都在同一个事务内

INSERT xxx
INSERT xxx

-- 提交:持久化
COMMIT
-- 回滚:回到原来的样子(失败!)
ROLLBACK

-- 事务结束
SET autocommit = 1 -- 开启自动提交

-- 了解即可
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点

6.4 事务实现转账

/*
A在线买一款价格为500元商品,网上银行转账.
A的银行卡余额为2000,然后给商家B支付500.
商家B一开始的银行卡余额为10000

创建数据库shop和创建表account并插入2条数据
*/

CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;

CREATE TABLE `account` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL,
`cash` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO account (`name`,`cash`)
VALUES('A',2000.00),('B',10000.00)

-- 转账实现
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION;  -- 开始一个事务,标记事务的起始点
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT; -- 提交事务
# rollback;
SET autocommit = 1; -- 恢复自动提交

7.索引

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。

7.1 索引的作用

  • 提高查询速度
  • 确保数据的唯一性
  • 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
  • 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
  • 全文检索字段进行搜索优化.

7.2 索引的分类

在一个表中,主键索引只能有一个,唯一索引可以有多个

  • 主键索引(PRIMARY KEY)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引(UNIQUE KEY)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
  • 常规索引 (KEY/INDEX)
    • 默认的,index,key关键字来设置
  • 全局索引 (FullText)
    • 在特定的数据库引擎下才有,MyISAM
    • 快速定位数据
-- 索引的使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后,增加索引

-- 显示所有的索引信息
SHOW INDEX FROM student

-- 增加一个全文索引(索引名,列名)
ALTER TABLE school.student ADD FULLTEXT INDEX studentName(studentName)

-- 删除索引
DROP  INDEX index_name ON table_name;

-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM student;-- 非全文索引

SELECT * FROM student WHERE MATCH(studentName) AGAINST('刘');

7.3 测试索引

参考文章https://mp.weixin.qq.com/s/-_-fRKNOi5rI6tb8RINZ0Q

建表app_user:

CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '用户昵称',
`email` varchar(50) NOT NULL COMMENT '用户邮箱',
`phone` varchar(20) DEFAULT '' COMMENT '手机号',
`gender` tinyint(4) unsigned DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` varchar(100) NOT NULL COMMENT '密码',
`age` tinyint(4) DEFAULT '0' COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表' 

批量插入数据:100w条

DROP FUNCTION IF EXISTS mock_data;
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i < num DO
  INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`)
   VALUES(CONCAT('用户', i), '[email protected]', CONCAT('18', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(), FLOOR(RAND()*100));
  SET i = i + 1;
END WHILE;
RETURN i;
END;
SELECT mock_data();

索引效率测试

无索引

SELECT * FROM app_user WHERE name = '用户9999'; -- 查看耗时
SELECT * FROM app_user WHERE name = '用户9999';
SELECT * FROM app_user WHERE name = '用户9999';

mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
          id: 1
select_type: SIMPLE
       table: app_user
  partitions: NULL
        type: ALL
possible_keys: NULL
        key: NULL
    key_len: NULL
        ref: NULL
        rows: 992759
    filtered: 10.00
      Extra: Using where
1 row in set, 1 warning (0.00 sec)

创建索引

CREATE INDEX idx_app_user_name ON app_user(name);

测试普通索引

mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
          id: 1
select_type: SIMPLE
       table: app_user
  partitions: NULL
        type: ref
possible_keys: idx_app_user_name
        key: idx_app_user_name
    key_len: 203
        ref: const
        rows: 1
    filtered: 100.00
      Extra: NULL
1 row in set, 1 warning (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

索引在小数据量的时候,用处不大,但是在大数据量的时候,区别十分明显~

7.4 索引原则

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表建议不要加索引
  • 索引一般应加在查找条件的字段
索引的数据结构

Hash类型的索引

Btree:InnoDB的默认数据结构

建议阅读: http://blog.codinglabs.org/articles/theory-of-mysql-index.html

8.权限管理和备份

原文链接:https://mp.weixin.qq.com/s/dCt_v5KQCTpgBdlY__0BSA

8.1 用户管理

使用SQLyog 创建用户,并授予权限演示

图片

8.1.1 基本命令

  • 创建用户

    -- CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串)
    CREATE USER cgz IDENTIFIED BY '123456'
    

    【注意】

    • 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。
    • 只能创建用户,不能赋予权限。
    • 用户名,注意引号:如 ‘user_name’@‘192.168.1.1’
    • 密码也需引号,纯数字密码也要加引号
    • 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD
  • 修改密码

    -- 修改当前用户密码
    SET PASSWORD = PASSWORD('密码')
    -- 修改指定用户密码
    SET PASSWORD FOR 用户名 = PASSWORD('密码')
    
  • 重命名用户

    -- RENAME USER old_user TO new_user
    RENAME USER cgz TO cgz2
    
  • 用户权限

    -- GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
    GRANT all privileges ON *.* TO cgz2
    
    • all privileges 表示所有权限
    • *.* 表示所有库的所有表
    • 库名.表名 表示某库下面的某表
  • 查看权限

    -- SHOW GRANTS FOR 用户名
    SHOW GRANTS FOR root@localhost;	-- 查看指定用户权限
    
    -- 查看当前用户权限
    SHOW GRANTS; 
    -- 或
    SHOW GRANTS FOR CURRENT_USER; 
    -- 或
    SHOW GRANTS FOR CURRENT_USER();
    
  • 撤销权限

    -- REVOKE 权限列表 ON 表名 FROM 用户名
    REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名    -- 撤销所有权限
    
  • 删除用户

    -- DROP USER 用户名
    DROP USER cgz2
    
  • 刷新权限

    FLUSH PRIVILEGES
    

8.1.2 权限解释

-- 权限列表
ALL [PRIVILEGES]    -- 设置除GRANT OPTION之外的所有简单权限
ALTER    -- 允许使用ALTER TABLE
ALTER ROUTINE    -- 更改或取消已存储的子程序
CREATE    -- 允许使用CREATE TABLE
CREATE ROUTINE    -- 创建已存储的子程序
CREATE TEMPORARY TABLES        -- 允许使用CREATE TEMPORARY TABLE
CREATE USER        -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
CREATE VIEW        -- 允许使用CREATE VIEW
DELETE    -- 允许使用DELETE
DROP    -- 允许使用DROP TABLE
EXECUTE        -- 允许用户运行已存储的子程序
FILE    -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE
INDEX     -- 允许使用CREATE INDEX和DROP INDEX
INSERT    -- 允许使用INSERT
LOCK TABLES        -- 允许对您拥有SELECT权限的表使用LOCK TABLES
PROCESS     -- 允许使用SHOW FULL PROCESSLIST
REFERENCES    -- 未被实施
RELOAD    -- 允许使用FLUSH
REPLICATION CLIENT    -- 允许用户询问从属服务器或主服务器的地址
REPLICATION SLAVE    -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)
SELECT    -- 允许使用SELECT
SHOW DATABASES    -- 显示所有数据库
SHOW VIEW    -- 允许使用SHOW CREATE VIEW
SHUTDOWN    -- 允许使用mysqladmin shutdown
SUPER    -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。
UPDATE    -- 允许使用UPDATE
USAGE    -- “无权限”的同义词
GRANT OPTION    -- 允许授予权限


/* 表维护 */

-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {
    QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

8.2 MySQL备份

数据库备份必要性

  • 保证重要数据不丢失
  • 数据转移

MySQL数据库备份方法

  • 数据库管理工具,如SQLyog
  • 直接拷贝数据库文件和相关配置文件
  • 使用命令行导出 mysqldump

mysqldump客户端

作用 :

  • 转储数据库
  • 搜集数据库进行备份
  • 将数据转移到另一个SQL服务器,不一定是MySQL服务器

图片

导出一张表
-- mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
mysqldump -uroot -p123456 school student >D:/a.sql
导出多张表
-- mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
mysqldump -uroot -p123456 school student result >D:/a.sql
导出所有表
-- mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
mysqldump -uroot -p123456 school >D:/a.sql
导出一个库
-- mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)
mysqldump -uroot -p123456 -B school >D:/a.sql
导入
-- 在登录mysql的情况下:source 备份文件
source D:/a.sql
-- 在不登录的情况下
mysql -u用户名 -p密码 库名 < 备份文件

9.规范数据库设计

9.1 为什么需要设计

当数据库比较复杂的时候,我们就需要设计了

糟糕的数据库数据:

  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦/异常【避免使用物理外键】
  • 程序的性能差

良好的数据库设计:

  • 节省内存空间
  • 保证数据的完整性
  • 方便我们开发系统

软件开发中,关于数据库设计

  • 分析需求,分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图E-R图

设计数据库的步骤:(个人博客)

  • 收集信息,分析需求

    • 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表()
    • 友链表(友链信息)
    • 自定义表(系统信息,某个关键字,或者一些主字段)key:value
    • 说说表(发表心情,id,content,create_time)
  • 标识实体(把需求落地到每个字段)

  • 标识实体 之间的关系

    • 写博客:user -->blog
    • 创建分类:user–>category
    • 关注:user -->user
    • 友链:links
    • 评论:user–>user–>blog

9.2 三大范式

为什么需要数据规范化?

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正常显示信息
  • 删除异常
    • 丢失有效的信息
三大范式

参考文章:https://www.cnblogs.com/wsg25/p/9615100.html

第一范式(1NF)

原子性:保证每一列不可再分

第二范式(2NF)

前提:满足第一范式

每张表只描述一件事情

第三范式(3NF)

前提:满足第一范式和第二范式

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

(规范数据库的设计)

规范性 和 性能的问题

关联查询的表不得超过三张表

  • 考虑商业化的需求和目标,(成本,用户体验)数据库的性能更加重要
  • 在规范性能的问题的时候,需要适当的考虑一下 规范性!
  • 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
  • 故意增加一些计算列(从大数据量降低为小数据量查询:索引)

你可能感兴趣的:(数据库,mysql,数据库)