0
点赞
收藏
分享

微信扫一扫

Java数据库篇_02 MySQL:这篇笔记的sql代码从头到尾敲一遍你就能掌握mysql数据库了

单调先生 2022-04-24 阅读 31

MySQL

Linux下操作mysql常用命令

安装mysql与首次配置

  1. 通过secureCRT工具连接Linux系统,在[root@localhost ~]下

  2. 上传 mysql 的安装包

    CRT中按快捷键 alt + p
    命令:pub 路径/文件名

   put D:/Linux/setup/mysql-5.7.27-1.el7.x86_64.rpm-bundle.tar
  1. 解压 mysql 的安装包
mkdir mysql
tar -xvf mysql-5.7.27-1.el7.x86_64.rpm-bundle.tar -C mysql/
  1. 安装客户端
cd mysql/
rpm -ivh mysql-community-client-5.7.27-1.el7.x86_64.rpm --force --nodeps
  1. 安装服务端
rpm -ivh mysql-community-server-5.7.27-1.el7.x86_64.rpm --force --nodeps
  1. 修改mysql默认字符集
vi /etc/my.cnf

添加如下内容:

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

在文件最下方添加

[client]
default-character-set=utf8
  1. 启动mysql服务
service mysqld start
  1. 登录mysql

mysql -u root -p 敲回车,输入密码

初始密码查看:cat /var/log/mysqld.log

在root@localhost: 后面的就是初始密码 =_KTekfpj8Ku

  1. 修改mysql登录密码
set global validate_password_policy=0;    
set global validate_password_length=1;
set password=password('密码');//password
  1. 授予远程连接权限
	//授权
grant all privileges on *.* to 'root' @'%' identified by 'password';
    
	//刷新
flush privileges;
  1. 关闭Linux系统防火墙
systemctl stop firewalld
  1. 重启mysql服务
service mysqld restart
  1. 使用SQLYog工具连接mysql
    注册
    用户名:ttrar
    密钥:三个皆可用
    59adfdfe-bcb0-4762-8267-d7fccf16beda
    8d8120df-a5c3-4989-8f47-5afc79c56e7c
    ec38d297-0543-4679-b098-4baadf91f983

SQLyog远程连接Linux服务器时出现错误2003处理

1.需要在cent7中开放端口,开放端口需要开启防火墙。

systemctl stop firewalld.service 关闭防火墙
systemctl start firewalld.service 开启防火墙

2.对3306端口进行防火墙配置

firewall-cmd --zone=public --add-port=3306/tcp --permanent

会返回success

3.重启防火墙

systemctl restart firewalld.service

4.iptables设置

vim /etc/sysconfig/iptables

5.添加如下代码,放开3306端口

-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT

6.重启防火墙

systemctl restart firewalld.service

7.查看开放的端口

firewall-cmd --list-ports

如果返回的参数有3306端口即为成功

再次测试SQLyog可以成功连接。

密码忘记了怎么办

1.net stop mysql
2.mysqld --skip-grant-tables
3.new cmd(管理员) 输入mysql
4.use mysql
5.update user set password=password(‘123456’) where user=‘root’
6.flush privileges;

DDL

数据库操作

数据库查询

查询所有数据库

SHOW DATABASES;

查询mysql数据库的创建语句

SHOW CREATE DATABASE mysql;

创建数据库

创建db1数据库

CREATE DATABASE db1;	

创建数据库db2(判断,如果不存在则创建)

CREATE DATABASE IF NOT EXISTS db2;

创建数据库db3、并指定字符集utf8

CREATE DATABASE db3 CHARACTER SET utf8;

查看db3数据库的字符集

SHOW CREATE DATABASE db3;

练习:创建db4数据库、如果不存在则创建,指定字符集为gbk

CREATE DATABASE IF NOT EXISTS db4 CHARACTER SET gbk;

查看db4数据库的字符集

SHOW CREATE DATABASE db4;

修改数据库

修改数据库db4的字符集为utf8

ALTER DATABASE db4 CHARACTER SET utf8;

查看db4数据库的字符集

SHOW CREATE DATABASE db4;

删除数据库

删除db1数据库

DROP DATABASE db1;

删除数据库db2,如果存在

DROP DATABASE IF EXISTS db2;

使用数据库

使用db4数据库

USE db4;

查询当前正在使用的数据库

SELECT DATABASE();

表操作

常见数据类型

int : 整数类型
double:小数类型
date:日期类型。包含年月日,格式yyyy-MM-dd
datatime:日期类型。包含年月日时分秒,格式yyyy-MM-dd HH:mm:ss
timestamp:时间戳类型。包含年月日时分秒,格式yyyy-MM-dd HH:mm:ss ,如果不给该列赋值、或赋值为null,则默认使用当前系统时间自动赋值。
varchar(长度):字符串类型

表查询

使用mysql数据库

USE mysql;

查询库中所有的表

SHOW TABLES;

查询user表结构

DESC USER;

查看mysql数据库中user表字符集

SHOW TABLE STATUS FROM mysql LIKE 'user';

创建表

标准语法:
	CREATE TABLE 表名(
		列名 数据类型 约束,
		列名 数据类型 约束,
		...
		列名 数据类型 约束
	);

创建一个product商品表(商品编号、商品名称、商品价格、商品库存、上架时间)

CREATE TABLE product(
	id INT,
	NAME VARCHAR(20),
	price DOUBLE,
	stock INT,
	insert_time DATE
);

查看product表详细结构

DESC product;

修改表

修改表名
标准语法:
	ALTER TABLE 旧表名 RENAME TO 新表名;

修改product表名为product2

ALTER TABLE product RENAME TO product2;
修改表的字符集
标准语法:
	ALTER TABLE 表名 CHARACTER SET 字符集名称;

查看db3数据库中product2数据表字符集

SHOW TABLE STATUS FROM db3 LIKE 'product2';

修改product2数据表字符集为gbk

ALTER TABLE product2 CHARACTER SET gbk;
给表添加列
标准语法:
	ALTER TABLE 表名 ADD 列名 数据类型;

给product2表添加一列color

ALTER TABLE product2 ADD color VARCHAR(10);
修改表中列的数据类型
标准语法:
	ALTER TABLE 表名 MODIFY 列名 数据类型;

将color数据类型修改为int

ALTER TABLE product2 MODIFY color INT;

查看product2表详细信息

DESC product2;
修改表中列的名称和数据类型
标准语法:
	ALTER TABLE 表名 CHANGE 旧列名 新列名 数据类型;

将color修改为address

ALTER TABLE product2 CHANGE color address VARCHAR(200);
删除表中的列
标准语法:
	ALTER TABLE 表名 DROP 列名;

删除address列

ALTER TABLE product2 DROP address;

删除表

删除product2表

DROP TABLE product2;

删除product2表,如果存在则删除

DROP TABLE IF EXISTS product2;

DML

新增表数据

给指定列添加数据(记录)
标准语法:
	INSERT INTO 表名(列名1,列名2,...) VALUES (值1,值2,...);

向product表添加一条数据

INSERT INTO product (id,NAME,price,stock,insert_time) VALUES (1,'手机',1999.99,25,'2020-02-02');

向product表添加指定列数据

INSERT INTO product (id,NAME,price) VALUES (2,'电脑',3999.99);
给全部列添加数据
标准语法:
	INSERT INTO 表名 VALUES (值1,值2,值3,...);

默认给全部列添加数据

INSERT INTO product VALUES (3,'冰箱',1500,35,'2030-03-03');
批量添加所有列数据
标准语法:
	INSERT INTO 表名 VALUES (值1,值2,值3,...),(值1,值2,值3,...),(值1,值2,值3,...);

批量添加数据

INSERT INTO product VALUES (4,'洗衣机',800,15,'2030-05-05'),(5,'微波炉',300,45,'2030-06-06');

修改表数据

修改表数据
标准语法:
	UPDATE 表名 SET 列名1 = 值1,列名2 = 值2,... [where 条件];

一定要注意加上where条件,否则它修改的是所有的记录的数据。

修改手机的价格为3500

UPDATE product SET price=3500 WHERE NAME='手机';

修改电脑的价格为1800、库存为36

UPDATE product SET price=1800,stock=36 WHERE NAME='电脑';

删除表数据

标准语法:
	DELETE FROM 表名 [WHERE 条件];

一定要注意加上where条件,否则它会删除表中所有的数据。

删除product表中的微波炉信息

DELETE FROM product WHERE NAME='微波炉';

删除product表中库存为10的商品信息

DELETE FROM product WHERE stock=10;

DQL

准备数据案例

创建db1数据库

CREATE DATABASE db1;

使用db1数据库

USE db1;

创建数据表

CREATE TABLE product(
	id INT,			-- 商品编号
	NAME VARCHAR(20),	-- 商品名称
	price DOUBLE,		-- 商品价格
	brand VARCHAR(10),	-- 商品品牌
	stock INT,		-- 商品库存
	insert_time DATE        -- 添加时间
);

添加数据

INSERT INTO product VALUES
(1,'华为手机',3999,'华为',23,'2088-03-10'),
(2,'小米手机',2999,'小米',30,'2088-05-15'),
(3,'苹果手机',5999,'苹果',18,'2088-08-20'),
(4,'华为电脑',6999,'华为',14,'2088-06-16'),
(5,'小米电脑',4999,'小米',26,'2088-07-08'),
(6,'苹果电脑',8999,'苹果',15,'2088-10-25'),
(7,'联想电脑',7999,'联想',NULL,'2088-11-11');

查询全部

查询语句的关键字顺序:

SELECT 字段列表
FROM 表名列表
WHERE 条件列表
GROUP BY 分组字段
HAVING 分组后的过滤条件
ORDER BY 排序
LIMIT 分页
查询全部数据
标准语法:
	SELECT * FROM 表名;

查询product表所有数据

SELECT * FROM product;
查询指定列
标准语法:
	SELECT 列名1,列名2,... FROM 表名;

查询名称、价格、品牌

SELECT NAME,price,brand FROM product;
去除重复查询
标准语法:
	SELECT DISTINCT 列名1,列名2,... FROM 表名;

查询品牌

SELECT brand FROM product;

查询品牌,去除重复

SELECT DISTINCT brand FROM product;
计算列的值
标准语法:
	SELECT 列名1 运算符(+ - * /) 列名2 FROM 表名;
	
如果某一列为null,可以进行替换
ifnull(表达式1,表达式2)
表达式1:想替换的列
表达式2:想替换的值

查询商品名称和库存,库存数量在原有基础上加10

SELECT NAME,stock+10 FROM product;

查询商品名称和库存,库存数量在原有基础上加10。进行null值判断

SELECT NAME,IFNULL(stock,0)+10 FROM product;
起别名
标准语法:
	SELECT 列名1,列名2,... AS 别名 FROM 表名;

查询商品名称和库存,库存数量在原有基础上加10。进行null值判断。起别名为getSum

SELECT NAME,IFNULL(stock,0)+10 AS getSum FROM product;
SELECT NAME,IFNULL(stock,0)+10 getSum FROM product;

条件查询

符号功能
>大于
<小于
>=大于等于
<=小于等于
=等于
<>或!=不等于
BETWEEN… AND…在某个范围之间内(都包含)
IN{…}多选一
LIKE占位符模糊查询 _单个任意字符 %多个任意字符
IS NULL是null
IS NOT NULL不是null
AND或&&并且
OR或 ||或者
NOT或!
条件查询
标准语法:
	SELECT 列名列表 FROM 表名 WHERE 条件;

查询库存大于20的商品信息

SELECT * FROM product WHERE stock > 20;

查询品牌为华为的商品信息

SELECT * FROM product WHERE brand='华为';

查询金额在4000 ~ 6000之间的商品信息

SELECT * FROM product WHERE price >= 4000 AND price <= 6000;
SELECT * FROM product WHERE price BETWEEN 4000 AND 6000;

查询库存为14、30、23的商品信息

SELECT * FROM product WHERE stock=14 OR stock=30 OR stock=23;
SELECT * FROM product WHERE stock IN(14,30,23);

查询库存为null的商品信息

SELECT * FROM product WHERE stock IS NULL;

查询库存不为null的商品信息

SELECT * FROM product WHERE stock IS NOT NULL;

查询名称以小米为开头的商品信息

SELECT * FROM product WHERE NAME LIKE '小米%';

查询名称第二个字是为的商品信息

SELECT * FROM product WHERE NAME LIKE '_为%';

查询名称为四个字符的商品信息

SELECT * FROM product WHERE NAME LIKE '____';

查询名称中包含电脑的商品信息

SELECT * FROM product WHERE NAME LIKE '%电脑%';

聚合函数查询

聚合函数是将一列数据作为一个整体,进行纵向的计算。
聚合函数的分类

函数名功能
count(列名)统计数量(一般选用不为null的列)
max(列名)最大值
min(列名)最小值
sum(列名)求和
avg(列名)平均值
标准语法:
	SELECT 函数名(列名) FROM 表名 [WHERE 条件];

计算product表中总记录条数

SELECT COUNT(*) FROM product;

获取最高价格

SELECT MAX(price) FROM product;

获取最低库存

SELECT MIN(stock) FROM product;

获取总库存数量

SELECT SUM(stock) FROM product;

获取品牌为苹果的总库存数量

SELECT SUM(stock) FROM product WHERE brand='苹果';

获取品牌为小米的平均商品价格

SELECT AVG(price) FROM product WHERE brand='小米';

排序查询

排序方式:ASC-升序,DESC-降序
如果有多个排序条件,只有当前边的条件值一样时,才会判断第二条件。

标准语法:
	SELECT 列名 FROM 表名 [WHERE 条件] ORDER BY 列名1 排序方式1,列名2 排序方式2;

按照库存升序排序

SELECT * FROM product ORDER BY stock ASC;

查询名称中包含手机的商品信息。按照金额降序排序

SELECT * FROM product WHERE NAME LIKE '%手机%' ORDER BY price DESC;

按照金额升序排序,如果金额相同,按照库存降序排列

SELECT * FROM product ORDER BY price ASC,stock DESC;

分组查询

标准语法:
	SELECT 列名 FROM 表名 [WHERE 条件] GROUP BY 分组列名 [HAVING 分组后条件过滤] [ORDER BY 排序列名 排序方式];

按照品牌分组,获取每组商品的总金额

SELECT brand,SUM(price) FROM product GROUP BY brand;

对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额

SELECT brand,SUM(price) FROM product WHERE price > 4000 GROUP BY brand;

对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额,只显示总金额大于7000元的

SELECT brand,SUM(price) getSum FROM product WHERE price > 4000 GROUP BY brand HAVING getSum > 7000;

对金额大于4000元的商品,按照品牌分组,获取每组商品的总金额,只显示总金额大于7000元的、并按照总金额的降序排列

SELECT brand,SUM(price) getSum FROM product 
WHERE price > 4000 
GROUP BY brand 
HAVING getSum > 7000 
ORDER BY getSum DESC;

分页查询

标准语法:
	SELECT 列名 FROM 表名 
	[WHERE 条件] 
	[GROUP BY 分组列名]
	[HAVING 分组后条件过滤] 
	[ORDER BY 排序列名 排序方式] 
	LIMIT 数据所在查询结果的位置,每页显示的条数;

每页显示3条数据

第1页 当前页数=(1-1) * 3

SELECT * FROM product LIMIT 0,3;

第2页 当前页数=(2-1) * 3

SELECT * FROM product LIMIT 3,3;

第3页 当前页数=(3-1) * 3

SELECT * FROM product LIMIT 6,3;

约束

约束作用
PRIMARY KEY主键约束
PRIMARY KEY AUTO_INCREMENT主键自增
UNIQUE唯一约束
NUT NULL非空约束
FOREIGN KEY外键约束
FOREIGN KEY ON UPDATE CASCADE外键级联更新
FOREIGN KEY ON DELETE CASCADE外键级联删除

主键 PRIMARY KEY

主键约束默认包含非空和唯一两个约束,一张表只能有一个主键,一般用于表中数据的唯一标识

创建学生表(编号、姓名、年龄) 编号设为主键

CREATE TABLE student(
	id INT PRIMARY KEY,
	NAME VARCHAR(30),
	age INT
);

查询学生表的详细信息

DESC student;

添加数据

INSERT INTO student VALUES (1,'张三',23);
INSERT INTO student VALUES (2,'李四',24);

删除主键

ALTER TABLE student DROP PRIMARY KEY;

建表后单独添加主键约束

ALTER TABLE student MODIFY id INT PRIMARY KEY;

主键自增约束是根据数据表中存在的记录自增,int类型会+1,当有自增的时候,主键可以设为null。

创建学生表(编号、姓名、年龄) 编号设为主键自增

CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30),
	age INT
);

查询学生表的详细信息

DESC student;

添加数据

INSERT INTO student VALUES (NULL,'张三',23),(NULL,'李四',24);

删除自增约束

ALTER TABLE student MODIFY id INT;
INSERT INTO student VALUES (NULL,'张三',23);

建表后单独添加自增约束

ALTER TABLE student MODIFY id INT AUTO_INCREMENT;

唯一 UNIQUE

唯一约束是使这个字段的数据在当前表中是唯一的,不能重复的。

创建学生表(编号、姓名、年龄) 编号设为主键自增,年龄设为唯一

CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30),
	age INT UNIQUE
);

查询学生表的详细信息

DESC student;

添加数据

INSERT INTO student VALUES (NULL,'张三',23);
INSERT INTO student VALUES (NULL,'李四',23);

删除唯一约束

ALTER TABLE student DROP INDEX age;

建表后单独添加唯一约束

ALTER TABLE student MODIFY age INT UNIQUE;

非空 NOT NULL

非空约束是你这个字段的数据不可以为null

创建学生表(编号、姓名、年龄) 编号设为主键自增,姓名设为非空,年龄设为唯一

CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30) NOT NULL,
	age INT UNIQUE
);

查询学生表的详细信息

DESC student;

添加数据

INSERT INTO student VALUES (NULL,'张三',23);

删除非空约束

ALTER TABLE student MODIFY NAME VARCHAR(30);
INSERT INTO student VALUES (NULL,NULL,25);

建表后单独添加非空约束

ALTER TABLE student MODIFY NAME VARCHAR(30) NOT NULL;

外键

使表和表之间产生关系,使数据更准确

CREATE DATABASE db2;
USE db2;
CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20) NOT NULL
);
INSERT INTO USER VALUES(NULL,'张三'),(NULL,'李四');
SELECT * FROM USER;

外键的名字叫ou_fk1,给uid字段添加外键,参照user表中的id字段

CREATE TABLE orderlist(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20) NOT NULL,
	uid INT,
	CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER (id)
);
INSERT INTO orderlist VALUES(NULL,'hm001',1),(NULL,'hm002',1),(NULL,'hm003',2),(NULL,'hm004',2);

删除外键约束

ALTER TABLE orderlist DROP FOREIGN KEY ou_fk1;

添加外键约束

ALTER TABLE orderlist ADD CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER (id);

外键级联更新和删除可以使相关联的两个表数据同步。
先删除外键约束

ALTER TABLE orderlist DROP FOREIGN KEY ou_fk1;

创建级联更新和删除约束,可以只添加一个

ALTER TABLE orderlist
ADD CONSTRAINT ou_fk1 
FOREIGN KEY (uid)
REFERENCES USER (id)
ON UPDATE CASCADE
ON DELETE CASCADE; 

当主表user中的id被修改和删除时,级联的表orderlist也会更新和删除

UPDATE USER SET id=3 WHERE id=2;
DELETE FROM USER WHERE id=3;

多表操作

表关系

多表
对于有一定关联关系的多张数据表,叫做多表,这些表之间的关系可以通过外键约束实现。
分类有一对一一对多多对多

一对一

建表原则:在任意一个表建立外键,去关联另一个表的主键。

在这里插入图片描述

-- 创建db3数据库
CREATE DATABASE db3;

-- 使用db3数据库
USE db3;

-- 创建person表
CREATE TABLE person(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(20)                        -- 姓名
);
-- 添加数据
INSERT INTO person VALUES (NULL,'张三'),(NULL,'李四');

-- 创建card表
CREATE TABLE card(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	number VARCHAR(20) UNIQUE NOT NULL,	-- 身份证号
	pid INT UNIQUE,                         -- 外键列
	CONSTRAINT cp_fk1 FOREIGN KEY (pid) REFERENCES person(id)
);
-- 添加数据
INSERT INTO card VALUES (NULL,'12345',1),(NULL,'56789',2);

一对多

建表原则:在“多”的一方建立外键约束,同时关联一的主键
在这里插入图片描述

-- 创建user表
CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(20)                        -- 姓名
);
-- 添加数据
INSERT INTO USER VALUES (NULL,'张三'),(NULL,'李四');

-- 创建orderlist表
CREATE TABLE orderlist(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	number VARCHAR(20),                     -- 订单编号
	uid INT,				-- 外键列
	CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id)
);
-- 添加数据
INSERT INTO orderlist VALUES (NULL,'hm001',1),(NULL,'hm002',1),(NULL,'hm003',2),(NULL,'hm004',2);



/*
	商品分类和商品
*/
-- 创建category表
CREATE TABLE category(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(10)                        -- 分类名称
);
-- 添加数据
INSERT INTO category VALUES (NULL,'手机数码'),(NULL,'电脑办公');

-- 创建product表
CREATE TABLE product(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(30),			-- 商品名称
	cid INT,				-- 外键列
	CONSTRAINT pc_fk1 FOREIGN KEY (cid) REFERENCES category(id)
);
-- 添加数据
INSERT INTO product VALUES (NULL,'华为P30',1),(NULL,'小米note3',1),
(NULL,'联想电脑',2),(NULL,'苹果电脑',2);

多对多

建表原则:需要借助第三张中间表,中间表中有两个列为外键,分别关联两张表的主键。

在这里插入图片描述

-- 创建student表
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(20)			-- 学生姓名
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三'),(NULL,'李四');

-- 创建course表
CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	NAME VARCHAR(10)			-- 课程名称
);
-- 添加数据
INSERT INTO course VALUES (NULL,'语文'),(NULL,'数学');


-- 创建中间表
CREATE TABLE stu_course(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 主键id
	sid INT,  -- 用于和student表中的id进行外键关联
	cid INT,  -- 用于和course表中的id进行外键关联
	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id), -- 添加外键约束
	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)   -- 添加外键约束
);
-- 添加数据
INSERT INTO stu_course VALUES (NULL,1,1),(NULL,1,2),(NULL,2,1),(NULL,2,2);

多表查询

数据准备

-- 创建db4数据库
CREATE DATABASE db4;
-- 使用db4数据库
USE db4;

-- 创建user表
CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 用户id
	NAME VARCHAR(20),			-- 用户姓名
	age INT                                 -- 用户年龄
);
-- 添加数据
INSERT INTO USER VALUES (1,'张三',23);
INSERT INTO USER VALUES (2,'李四',24);
INSERT INTO USER VALUES (3,'王五',25);
INSERT INTO USER VALUES (4,'赵六',26);


-- 订单表
CREATE TABLE orderlist(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 订单id
	number VARCHAR(30),			-- 订单编号
	uid INT,    -- 外键字段
	CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id)
);
-- 添加数据
INSERT INTO orderlist VALUES (1,'hm001',1);
INSERT INTO orderlist VALUES (2,'hm002',1);
INSERT INTO orderlist VALUES (3,'hm003',2);
INSERT INTO orderlist VALUES (4,'hm004',2);
INSERT INTO orderlist VALUES (5,'hm005',3);
INSERT INTO orderlist VALUES (6,'hm006',3);
INSERT INTO orderlist VALUES (7,'hm007',NULL);


-- 商品分类表
CREATE TABLE category(
	id INT PRIMARY KEY AUTO_INCREMENT,  -- 商品分类id
	NAME VARCHAR(10)                    -- 商品分类名称
);
-- 添加数据
INSERT INTO category VALUES (1,'手机数码');
INSERT INTO category VALUES (2,'电脑办公');
INSERT INTO category VALUES (3,'烟酒茶糖');
INSERT INTO category VALUES (4,'鞋靴箱包');


-- 商品表
CREATE TABLE product(
	id INT PRIMARY KEY AUTO_INCREMENT,   -- 商品id
	NAME VARCHAR(30),                    -- 商品名称
	cid INT, -- 外键字段
	CONSTRAINT cp_fk1 FOREIGN KEY (cid) REFERENCES category(id)
);
-- 添加数据
INSERT INTO product VALUES (1,'华为手机',1);
INSERT INTO product VALUES (2,'小米手机',1);
INSERT INTO product VALUES (3,'联想电脑',2);
INSERT INTO product VALUES (4,'苹果电脑',2);
INSERT INTO product VALUES (5,'中华香烟',3);
INSERT INTO product VALUES (6,'玉溪香烟',3);
INSERT INTO product VALUES (7,'计生用品',NULL);


-- 中间表
CREATE TABLE us_pro(
	upid INT PRIMARY KEY AUTO_INCREMENT,  -- 中间表id
	uid INT, -- 外键字段。需要和用户表的主键产生关联
	pid INT, -- 外键字段。需要和商品表的主键产生关联
	CONSTRAINT up_fk1 FOREIGN KEY (uid) REFERENCES USER(id),
	CONSTRAINT up_fk2 FOREIGN KEY (pid) REFERENCES product(id)
);
-- 添加数据
INSERT INTO us_pro VALUES (NULL,1,1);
INSERT INTO us_pro VALUES (NULL,1,2);
INSERT INTO us_pro VALUES (NULL,1,3);
INSERT INTO us_pro VALUES (NULL,1,4);
INSERT INTO us_pro VALUES (NULL,1,5);
INSERT INTO us_pro VALUES (NULL,1,6);
INSERT INTO us_pro VALUES (NULL,1,7);
INSERT INTO us_pro VALUES (NULL,2,1);
INSERT INTO us_pro VALUES (NULL,2,2);
INSERT INTO us_pro VALUES (NULL,2,3);
INSERT INTO us_pro VALUES (NULL,2,4);
INSERT INTO us_pro VALUES (NULL,2,5);
INSERT INTO us_pro VALUES (NULL,2,6);
INSERT INTO us_pro VALUES (NULL,2,7);
INSERT INTO us_pro VALUES (NULL,3,1);
INSERT INTO us_pro VALUES (NULL,3,2);
INSERT INTO us_pro VALUES (NULL,3,3);
INSERT INTO us_pro VALUES (NULL,3,4);
INSERT INTO us_pro VALUES (NULL,3,5);
INSERT INTO us_pro VALUES (NULL,3,6);
INSERT INTO us_pro VALUES (NULL,3,7);
INSERT INTO us_pro VALUES (NULL,4,1);
INSERT INTO us_pro VALUES (NULL,4,2);
INSERT INTO us_pro VALUES (NULL,4,3);
INSERT INTO us_pro VALUES (NULL,4,4);
INSERT INTO us_pro VALUES (NULL,4,5);
INSERT INTO us_pro VALUES (NULL,4,6);
INSERT INTO us_pro VALUES (NULL,4,7);

内连接

内连接就是在多个表中查询满足条件的记录。

/*
	显示内连接
	标准语法:
		SELECT 列名 FROM 表名1 [INNER] JOIN 表名2 ON 关联条件;
*/
-- 查询用户信息和对应的订单信息
SELECT * FROM USER INNER JOIN orderlist ON orderlist.uid = user.id;

-- 查询用户信息和对应的订单信息,起别名
SELECT * FROM USER u INNER JOIN orderlist o ON o.uid=u.id;

-- 查询用户姓名,年龄。和订单编号
SELECT
	u.name,		-- 用户姓名
	u.age,		-- 用户年龄
	o.number	-- 订单编号
FROM
	USER u          -- 用户表
INNER JOIN
	orderlist o     -- 订单表
ON
	o.uid=u.id;

/*
	隐式内连接
	标准语法:
		SELECT 列名 FROM 表名1,表名2 WHERE 关联条件;
*/
-- 查询用户姓名,年龄。和订单编号
SELECT
	u.name,		-- 用户姓名
	u.age,		-- 用户年龄
	o.number	-- 订单编号
FROM
	USER u,		-- 用户表
	orderlist o     -- 订单表
WHERE
	o.uid=u.id;

外连接

外连接就是从两个表中查询,获取其中一个表的全部记录的数据,以及获取另一个表中的交集的数据。

/*
	左外连接
	标准语法:
		SELECT 列名 FROM 表名1 LEFT [OUTER] JOIN 表名2 ON 条件;
*/
-- 查询所有用户信息,以及用户对应的订单信息
SELECT
	u.*,
	o.number
FROM
	USER u
LEFT OUTER JOIN
	orderlist o
ON
	o.uid=u.id;
	
/*
	右外连接
	标准语法:
		SELECT 列名 FROM 表名1 RIGHT [OUTER] JOIN 表名2 ON 条件;
*/
-- 查询所有订单信息,以及订单所属的用户信息
SELECT
	o.*,
	u.name
FROM
	USER u
RIGHT OUTER JOIN
	orderlist o
ON
	o.uid=u.id;

子查询

子查询是在查询语句中嵌套了其他的查询语句,我们将嵌套的查询称为子查询。子查询可以将查询的结果作为另一条语句的查询条件。

/*
	结果是单行单列的
	标准语法:
		SELECT 列名 FROM 表名 WHERE 列名=(SELECT 列名 FROM 表名 [WHERE 条件]);
*/
-- 查询年龄最高的用户姓名
SELECT MAX(age) FROM USER;
SELECT NAME,age FROM USER WHERE age=(SELECT MAX(age) FROM USER);

/*
	结果是多行单列的
	标准语法:
		SELECT 列名 FROM 表名 WHERE 列名 [NOT] IN (SELECT 列名 FROM 表名 [WHERE 条件]); 
*/
-- 查询张三和李四的订单信息
SELECT * FROM orderlist WHERE uid IN (1,2);
SELECT id FROM USER WHERE NAME IN ('张三','李四');
SELECT * FROM orderlist WHERE uid IN (SELECT id FROM USER WHERE NAME IN ('张三','李四'));

/*
	结果是多行多列的
	标准语法:
		SELECT 列名 FROM 表名 [别名],(SELECT 列名 FROM 表名 [WHERE 条件]) [别名] [WHERE 条件];
*/
-- 查询订单表中id大于4的订单信息和所属用户信息
SELECT * FROM orderlist WHERE id > 4;
SELECT
	u.name,
	o.number
FROM
	USER u,
	(SELECT * FROM orderlist WHERE id > 4) o
WHERE
	o.uid=u.id;

自关联

自关联查询是在一个表关联查询。

-- 创建员工表
CREATE TABLE employee(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 员工编号
	NAME VARCHAR(20),			-- 员工姓名
	mgr INT,				-- 上级编号
	salary DOUBLE				-- 员工工资
);
-- 添加数据
INSERT INTO employee VALUES (1001,'孙悟空',1005,9000.00),
(1002,'猪八戒',1005,8000.00),
(1003,'沙和尚',1005,8500.00),
(1004,'小白龙',1005,7900.00),
(1005,'唐僧',NULL,15000.00),
(1006,'武松',1009,7600.00),
(1007,'李逵',1009,7400.00),
(1008,'林冲',1009,8100.00),
(1009,'宋江',NULL,16000.00);


-- 查询所有员工的姓名及其直接上级的姓名,没有上级的员工也需要查询
/*
分析
	员工信息 employee表
	条件:employee.mgr = employee.id
	查询左表的全部数据,和左右两张表有交集部分数据,左外连接
*/
SELECT
	e1.id,
	e1.name,
	e1.mgr,
	e2.id,
	e2.name
FROM
	employee e1
LEFT OUTER JOIN
	employee e2
ON
	e1.mgr = e2.id;

练习

-- 1.查询用户的编号、姓名、年龄。订单编号
/*
分析
	用户的编号、姓名、年龄  user表      订单编号 orderlist表
	条件:user.id=orderlist.uid
*/
SELECT
	u.id,
	u.name,
	u.age,
	o.number
FROM
	USER u,
	orderlist o
WHERE
	u.id=o.uid;



-- 2.查询所有的用户。用户的编号、姓名、年龄。订单编号
/*
分析
	用户的编号、姓名、年龄  user表    订单编号 orderlist表
	条件:user.id=orderlist.uid
	查询所有的用户,左外连接
*/
SELECT
	u.id,
	u.name,
	u.age,
	o.number
FROM
	USER u
LEFT OUTER JOIN
	orderlist o
ON
	u.id=o.uid;



-- 3.查询所有的订单。用户的编号、姓名、年龄。订单编号
/*
分析
	用户的编号、姓名、年龄 user表    订单编号 orderlist表
	条件:user.id=orderlist.uid
	查询所有的订单,右外连接
*/
SELECT
	u.id,
	u.name,
	u.age,
	o.number
FROM
	USER u
RIGHT OUTER JOIN
	orderlist o
ON
	u.id=o.uid;

	

-- 4.查询用户年龄大于23岁的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析
	用户的编号、姓名、年龄 user表    订单编号 orderlist表
	条件:user.id=orderlist.uid AND user.age > 23
*/
SELECT
	u.id,
	u.name,
	u.age,
	o.number
FROM
	USER u,
	orderlist o
WHERE
	u.id=o.uid
	AND
	u.age > 23;


-- 5.查询张三和李四用户的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析
	用户的编号、姓名、年龄 user表   订单编号 orderlist表
	条件:user.id=orderlist.uid AND user.name IN ('张三','李四')
*/
SELECT
	u.id,
	u.name,
	u.age,
	o.number
FROM
	USER u,
	orderlist o
WHERE
	u.id=o.uid
	AND
	u.name IN ('张三','李四');


-- 6.查询商品分类的编号、分类名称。分类下的商品名称
/*
分析
	商品分类的编号、分类名称 category表    商品名称 product表
	条件:category.id=product.cid
*/
SELECT
	c.id,
	c.name,
	p.name
FROM
	category c,
	product p
WHERE
	c.id=p.cid;


-- 7.查询所有的商品分类。商品分类的编号、分类名称。分类下的商品名称
/*
分析
	商品分类的编号、分类名称 category表    商品名称 product表
	条件:category.id=product.cid
	查询所有的商品分类,左外连接
*/
SELECT
	c.id,
	c.name,
	p.name
FROM
	category c
LEFT OUTER JOIN
	product p
ON
	c.id=p.cid;


-- 8.查询所有的商品信息。商品分类的编号、分类名称。分类下的商品名称
/*
分析
	商品分类的编号、分类名称  category表   商品名称 product表
	条件:category.id=product.cid
	查询所有的商品信息,右外连接
*/
SELECT
	c.id,
	c.name,
	p.name
FROM
	category c
RIGHT OUTER JOIN
	product p
ON
	c.id=p.cid;



-- 9.查询所有的用户和该用户能查看的所有的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析
	用户的编号、姓名、年龄 user表   商品名称 product表    中间表 us_pro
	条件:us_pro.uid=user.id AND us_pro.pid=product.id
*/
SELECT
	u.id,
	u.name,
	u.age,
	p.name
FROM
	USER u,
	product p,
	us_pro up
WHERE
	up.uid=u.id
	AND
	up.pid=p.id;



-- 10.查询张三和李四这两个用户可以看到的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析
	用户的编号、姓名、年龄 user表   商品名称 product表   中间表 us_pro
	条件:us_pro.uid=user.id AND us_pro.pid=product.id AND user.name IN ('张三','李四') 
*/
SELECT
	u.id,
	u.name,
	u.age,
	p.name
FROM
	USER u,
	product p,
	us_pro up
WHERE
	up.uid=u.id
	AND
	up.pid=p.id
	AND
	u.name IN ('张三','李四');

视图

视图(View)是一种虚拟存在的数据表,或者说并不是在数据库中真实存在的数据表。它的作用是将一些较为复杂的查询结果,封装到一个虚拟表中,后期有相同的需求就直接查询这个虚拟表即可。

数据准备

-- 创建db5数据库
CREATE DATABASE db5;

-- 使用db5数据库
USE db5;

-- 创建country表
CREATE TABLE country(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 国家id
	NAME VARCHAR(30)                        -- 国家名称
);
-- 添加数据
INSERT INTO country VALUES (NULL,'中国'),(NULL,'美国'),(NULL,'俄罗斯');

-- 创建city表
CREATE TABLE city(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 城市id
	NAME VARCHAR(30),			-- 城市名称
	cid INT, -- 外键列。关联country表的主键列id
	CONSTRAINT cc_fk1 FOREIGN KEY (cid) REFERENCES country(id)  -- 添加外键约束
);
-- 添加数据
INSERT INTO city VALUES (NULL,'北京',1),(NULL,'上海',1),(NULL,'纽约',2),(NULL,'莫斯科',3);

创建视图

标准语法
	CREATE VIEW 视图名称 [(列名列表)] AS 查询语句;

创建city_country视图,保存城市和国家的信息(使用指定列名)

CREATE VIEW city_country (city_id,city_name,country_name) AS
SELECT
	c1.id,
	c1.name,
	c2.name
FROM
	city c1,
	country c2
WHERE
	c1.cid=c2.id;

查询视图

标准语法
	SELECT * FROM 视图名称;

查询视图

SELECT * FROM city_country;

修改视图

修改视图数据
标准语法
	UPDATE 视图名称 SET 列名=值 WHERE 条件;

修改视图结构
标准语法
	ALTER VIEW 视图名称 (列名列表) AS 查询语句; 

修改视图数据,将北京修改为深圳。(注意:修改视图数据后,源表中的数据也会随之修改)

SELECT * FROM city_country;
UPDATE city_country SET city_name='深圳' WHERE city_name='北京';

将视图中的country_name修改为name

ALTER VIEW city_country (city_id,city_name,NAME) AS
SELECT
	c1.id,
	c1.name,
	c2.name
FROM
	city c1,
	country c2
WHERE
	c1.cid=c2.id;

删除视图

标准语法
	DROP VIEW [IF EXISTS] 视图名称;

删除city_country视图

DROP VIEW IF EXISTS city_country;

备份和恢复

命令行方式

备份
登录到MySQL服务器,输入:
mysqldump -u root -p 数据库名称 > 文件保存路径

[root@localhost ~]# mysqldump -u root -p db5 > /root/db5.sql
Enter password: 
[root@localhost ~]# ls
anaconda-ks.cfg  db5.sql  initial-setup-ks.cfg  mysql  公共  模板  视频  图片  文档  下载  音乐  桌面
[root@localhost ~]# cat db5.sql

恢复
1.登录到MySQL数据库

[root@localhost ~]# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.

查看数据库

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db2                |
| db3                |
| db4                |
| db5                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

2.删除已备份的数据库。

 drop database db5;

再查看发现db5没有了

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| db2                |
| db3                |
| db4                |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
8 rows in set (0.00 sec)

3.重新创建名称相同的数据。

mysql> create database db5;
Query OK, 1 row affected (0.00 sec)

4.使用该数据库。

 use db5;

5.导入文件执行:source备份文件全路径。

 source /root/db5.sql

图形化界面方式(SQLyog)

备份
右键想要备份的数据库,找到备份和导出,选择备份数据库,转存储到sql
在这里插入图片描述
然后设置存储的位置,点击导出即可。
在这里插入图片描述
恢复
依旧是先删掉原来的数据库,然后再创建一个
在这里插入图片描述
这次右键选择导入,执行sql脚本
在这里插入图片描述
选择执行的文件
在这里插入图片描述
点击执行,这样数据库就恢复完成了。

存储过程和函数

存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合。

存储过程和函数能提高代码的复用性,减少数据在数据库和应用服务器之间的传输,提高效率;还能减少代码层面的业务处理。

存储过程和函数的区别:
存储函数必须有返回值;
存储过程可以没有返回值。

数据准备

-- 创建db6数据库
CREATE DATABASE db6;

-- 使用db6数据库
USE db6;

-- 创建学生表
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 学生id
	NAME VARCHAR(20),			-- 学生姓名
	age INT,				-- 学生年龄
	gender VARCHAR(5),			-- 学生性别
	score INT                               -- 学生成绩
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'男',95),(NULL,'李四',24,'男',98),
(NULL,'王五',25,'女',100),(NULL,'赵六',26,'女',90);

-- 按照性别进行分组,查询每组学生的总成绩。按照总成绩的升序排序
SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;

创建存储过程

-- 修改分隔符为$
DELIMITER $
-- 标准语法
CREATE PROCEDURE 存储过程名称(参数列表)
BEGIN
	SQL 语句列表;
END$
-- 修改分隔符为分号
DELIMITER ;

创建stu_group()存储过程,封装 分组查询总成绩,并按照总成绩升序排序的功能

DELIMITER $

CREATE PROCEDURE stu_group()
BEGIN
	SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;
END$

DELIMITER ;

调用存储过程

CALL 存储过程名称(实际参数);

调用stu_group()存储过程

CALL stu_group();

查询存储过程

查询数据库中所有的存储过程

SELECT * FROM mysql.proc WHERE db='数据库名称';

查看db6数据库中所有的存储过程

SELECT * FROM mysql.proc WHERE db='db6';

删除存储过程

DROP PROCEDURE [IF EXISTS] 存储过程名称;
DROP PROCEDURE IF EXISTS stu_group;

变量

定义变量
DECLARE 变量名 数据类型 [DEFAULT 默认值];

定义一个int类型变量,并赋默认值为10

DELIMITER $

CREATE PROCEDURE pro_test1()
BEGIN
	-- 定义变量
	DECLARE num INT DEFAULT 10;
	-- 使用变量
	SELECT num;
END$
DELIMITER ;

-- 调用pro_test1存储过程
CALL pro_test1();
变量赋值-方式一
SET 变量名 = 变量值;

定义一个varchar类型变量并赋值

DELIMITER $

CREATE PROCEDURE pro_test2()
BEGIN
	-- 定义变量
	DECLARE NAME VARCHAR(10);
	-- 为变量赋值
	SET NAME = '存储过程';
	-- 使用变量
	SELECT NAME;
END$
DELIMITER ;

-- 调用pro_test2存储过程
CALL pro_test2();
变量赋值-方式二
SELECT 列名 INTO 变量名 FROM 表名 [WHERE 条件];

定义两个int变量,用于存储男女同学的总分数

DELIMITER $

CREATE PROCEDURE pro_test3()
BEGIN
	-- 定义两个变量
	DECLARE men,women INT;
	-- 查询男同学的总分数,为men赋值
	SELECT SUM(score) INTO men FROM student WHERE gender='男';
	-- 查询女同学的总分数,为women赋值
	SELECT SUM(score) INTO women FROM student WHERE gender='女';
	-- 使用变量
	SELECT men,women;
END$
DELIMITER ;

-- 调用pro_test3存储过程
CALL pro_test3();

if语句

IF 判断条件1 THEN 执行的sql语句1;
[ELSEIF 判断条件2 THEN 执行的sql语句2;]
...
[ELSE 执行的sql语句n;]
END IF;

定义一个int变量,用于存储班级总成绩
定义一个varchar变量,用于存储分数描述
根据总成绩判断:
380分及以上 学习优秀
320 ~ 380 学习不错
320以下 学习一般

DELIMITER $

CREATE PROCEDURE pro_test4()
BEGIN
	-- 定义变量
	DECLARE total INT;
	DECLARE info VARCHAR(10);
	-- 查询总成绩,为total赋值
	SELECT SUM(score) INTO total FROM student;
	-- 对总成绩判断
	IF total > 380 THEN
		SET info = '学习优秀';
	ELSEIF total >= 320 AND total <= 380 THEN
		SET info = '学习不错';
	ELSE
		SET info = '学习一般';
	END IF;
	-- 查询总成绩和描述信息
	SELECT total,info;
END$
DELIMITER ;

-- 调用pro_test4存储过程
CALL pro_test4();

参数传递

CREATE PROCEDURE 存储过程名称([IN|OUT|INOUT] 参数名 数据类型)
BEGIN
	SQL 语句列表;
END$

输入总成绩变量,代表学生总成绩
输出分数描述变量,代表学生总成绩的描述信息
根据总成绩判断:
380分及以上 学习优秀
320 ~ 380 学习不错
320以下 学习一般

DELIMITER $

CREATE PROCEDURE pro_test5(IN total INT,OUT info VARCHAR(10))
BEGIN
	-- 对总成绩判断
	IF total > 380 THEN
		SET info = '学习优秀';
	ELSEIF total >= 320 AND total <= 380 THEN
		SET info = '学习不错';
	ELSE
		SET info = '学习一般';
	END IF;
END$

DELIMITER ;

-- 调用pro_test5存储过程
CALL pro_test5(350,@info);

CALL pro_test5((SELECT SUM(score) FROM student),@info);

SELECT @info;

while循环

初始化语句;
WHILE 条件判断语句 DO
	循环体语句;
	条件控制语句;
END WHILE;

计算1~100之间的偶数和

DELIMITER $

CREATE PROCEDURE pro_test6()
BEGIN
	-- 定义求和变量
	DECLARE result INT DEFAULT 0;
	-- 定义初始化变量
	DECLARE num INT DEFAULT 1;
	-- while循环
	WHILE num <= 100 DO
		IF num % 2 = 0 THEN
			SET result = result + num;
		END IF;
		
		SET num = num + 1;
	END WHILE;
	
	-- 查询求和结果
	SELECT result;
END$

DELIMITER ;

-- 调用pro_test6存储过程
CALL pro_test6();

存储函数

创建存储函数
CREATE FUNCTION 函数名称([参数 数据类型])
RETURNS 返回值类型
BEGIN
	执行的sql语句;
	RETURN 结果;
END$

定义存储函数,获取学生表中成绩大于95分的学生数量

DELIMITER $

CREATE FUNCTION fun_test1()
RETURNS INT
BEGIN
	-- 定义变量
	DECLARE s_count INT;
	-- 查询成绩大于95分的数量,为s_count赋值
	SELECT COUNT(*) INTO s_count FROM student WHERE score > 95;
	-- 返回统计结果
	RETURN s_count;
END$

DELIMITER ;
调用函数
SELECT 函数名称(实际参数);
-- 调用函数
SELECT fun_test1();
删除函数
DROP FUNCTION 函数名称;
-- 删除函数
DROP FUNCTION fun_test1;

触发器

触发器是与表有关的数据库对象,可以在insert、update、 delete 之前或之后触发并执行触发器中定义的SQL语句。
这种特性可以协助应用系统在数据库端确保数据的完整性、日志记录数据校验等操作。
使用别名NEW和OLD来引用触发器中发生变化的内容记录。
NEW表示操作(INSERT、UPDATE、DELETE)后新的数据,OLD表示操作之前的数据。

数据准备

-- 创建db7数据库
CREATE DATABASE db7;

-- 使用db7数据库
USE db7;

-- 创建账户表account
CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 账户id
	NAME VARCHAR(20),			-- 姓名
	money DOUBLE				-- 余额
);
-- 添加数据
INSERT INTO account VALUES (NULL,'张三',1000),(NULL,'李四',1000);


-- 创建日志表account_log
CREATE TABLE account_log(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 日志id
	operation VARCHAR(20),			-- 操作类型 (insert update delete)
	operation_time DATETIME,		-- 操作时间
	operation_id INT,			-- 操作表的id
	operation_params VARCHAR(200)       	-- 操作参数
);

创建触发器

DELIMITER $

CREATE TRIGGER 触发器名称
BEFORE|AFTER INSERT|UPDATE|DELETE
ON 表名
FOR EACH ROW
BEGIN
	触发器要执行的功能;
END$

DELIMITER ;

创建INSERT型触发器。用于对account表新增数据进行日志的记录

DELIMITER $

CREATE TRIGGER account_insert
AFTER INSERT
ON account
FOR EACH ROW
BEGIN
	INSERT INTO account_log VALUES (NULL,'INSERT',NOW(),new.id,CONCAT('插入后{id=',new.id,',name=',new.name,',money=',new.money,'}'));
END$

DELIMITER ;

向account表添加一条记录

INSERT INTO account VALUES (NULL,'王五',2000);

查询account表

SELECT * FROM account;

查询account_log表

SELECT * FROM account_log;

创建UPDATE型触发器。用于对account表修改数据进行日志的记录

DELIMITER $

CREATE TRIGGER account_update
AFTER UPDATE
ON account
FOR EACH ROW
BEGIN
	INSERT INTO account_log VALUES (NULL,'UPDATE',NOW(),new.id,CONCAT('更新前{id=',old.id,',name=',old.name,',money=',old.money,'}','更新后{id=',new.id,',name=',new.name,',money=',new.money,'}'));
END$

DELIMITER ;


-- 修改account表中李四的金额为2000
UPDATE account SET money=2000 WHERE id=2;

-- 查询account表
SELECT * FROM account;

-- 查询account_log表
SELECT * FROM account_log;

创建DELETE型触发器。用于对account表删除数据进行日志的记录

DELIMITER $

CREATE TRIGGER account_delete
AFTER DELETE
ON account
FOR EACH ROW
BEGIN
	INSERT INTO account_log VALUES (NULL,'DELETE',NOW(),old.id,CONCAT('删除前{id=',old.id,',name=',old.name,',money=',old.money,'}'));
END$

DELIMITER ;

-- 删除account表中王五
DELETE FROM account WHERE id=3;

-- 查询account表
SELECT * FROM account;

-- 查询account_log表
SELECT * FROM account_log;

查看、删除触发器

/*
	查看触发器
	SHOW TRIGGERS;
*/
-- 查看触发器
SHOW TRIGGERS;

/*
	删除触发器
	DROP TRIGGER 触发器名称;
*/
-- 删除account_delete触发器
DROP TRIGGER account_delete;

事务

事务: 原子性。即一条或多条SQL语句组成一个执行单元,其特点是这个单元要么都成功要么都失败。单元中的每条SQL语句都相互依赖,形成一个整体。
如果某条SQL语句执行失败或者出现错误,那么整个单元就会撤回到事务最初的状态。
如果单元中所有的SQL语句都执行成功,则事务就顺利执行。

开启、回滚、提交事务

开启事务:START TRANSACTION;

回滚事务:ROLLBACK;
当我们在一次性执行多条sql语句时,我们期望一起执行。
但是当有sql语句执行失败时,我们可以通过回滚事务回到开启事务时的状态。

提交事务:COMMIT;
当所有的sql语句执行成功时,这时才提交事务。

事务的提交方式

事务的四大特征(ACID)

原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功提交,要么全部失败回滚
因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

一致性(Consistency)
一致性是指事务必须使数据库从一 个致性状态变换到另一 个致性状态。也就是说一个事务执行之前和执行之后都必须处于致性状态。

隔离性(isolcation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务。不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

持久性(durability)
持久性是指一个事务一旦被提交 了,那么对数据库中的数据的改变就是永久性的。即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的隔离级别

多个客户端操作时,各个客户端的事务之间应该是隔离的,相互独立的,不受影响的。而如果多个事务操作同一批数据时,就会产性不同的问题,我们需要设置不同的隔离级别来解决这些问题。

隔离级别名称会引发的问题
read uncommitted读未提交脏读、不可重复读、幻读
read committed读已提交不可重复读、幻读
repeatable read可重复读幻读
serializable串行化

脏读: 在一个事务处理过程中读取到了另一个未提交事务中的数据,导致两次查询结果不一致。
不可重复读:在一个事务处理过程中读取到了另一个事务中修改并已提交的数据,导致两次查询结果不一致。
幻读:查询某数据不存在,准备插入此记录,但执行插入时发现此记录已存在,无法插入。或查询数据不存在执行删除操作,却发现删除成功

隔离级别从小到大安全性越来越高,但是效率越来越低,所以不建议修改数据库默认的隔离级别。

查询隔离级别:SELECT @@TX_ISOLATION;
修改隔离级别:SET GLOBAL TRANSACTION ISOLATION LEVEL 级别字符串;

查询事务隔离级别

SELECT @@tx_isolation;

修改事务隔离级别(修改后需要重新连接)

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

脏读问题及解决

脏读:一个事务中读取到了其他事务未提交的数据

解决脏读问题方式:设置事务隔离级别为read uncommitted

SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
开启两个用于演示的事务:
在窗口2中能获取到窗口1中还没有提交或回滚的数据
窗口1演示事务

开启事务

START TRANSACTION;

转账

UPDATE account SET money = money-500 WHERE NAME='张三';
UPDATE account SET money = money+500 WHERE NAME='李四';

查询account表

SELECT * FROM account;

回滚

ROLLBACK;

提交事务

COMMIT;
窗口2演示事务

查询事务隔离级别

SELECT @@tx_isolation;

开启事务

START TRANSACTION;

查询account表

SELECT * FROM account;

提交事务

COMMIT;

不可重复读问题及解决

不可重复读:一个事务中读取到了其他事务已提交的数据

设置事务隔离级别为read committed
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

开启两个用于演示的事务:
发生的问题:在窗口2未提交时能查询到窗口1中已经提交的数据
解决后:
read committed级别时,
必须在窗口2中也提交数据才能查看到窗口1修改后的数据

窗口1演示事务

开启事务

START TRANSACTION;

转账

UPDATE account SET money = money-500 WHERE NAME='张三';
UPDATE account SET money = money+500 WHERE NAME='李四';

查询account表

SELECT * FROM account;

提交事务

COMMIT;
窗口2演示事务

查询隔离级别

SELECT @@tx_isolation;

开启事务

START TRANSACTION;

查询account表

SELECT * FROM account;

提交事务

COMMIT;

幻读问题及解决

查询某记录是否存在,不存在
准备插入此记录,但执行插入时发现此记录已存在,无法插入
-- 设置隔离级别为repeatable read
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 开启事务
START TRANSACTION;

-- 添加记录
INSERT INTO account VALUES (3,'王五',2000);
INSERT INTO account VALUES (4,'赵六',3000);

-- 查询account表
SELECT * FROM account;

-- 提交事务
COMMIT;
-- 查询隔离级别
SELECT @@tx_isolation;

-- 开启事务
START TRANSACTION;

-- 查询account表
SELECT * FROM account;

-- 添加
INSERT INTO account VALUES (3,'王五',2000);

-- 提交事务
COMMIT;

存储引擎

存储引擎相关操作

查询数据库支持的存储引擎
SHOW ENGINES;

查询数据库支持的存储引擎

SHOW ENGINES;
查询某个数据库中所有数据表的存储引擎
SHOW TABLE STATUS FROM 数据库名称;

查询db4数据库所有表的存储引擎

SHOW TABLE STATUS FROM db4;
查询某个数据库中某个表的存储引擎
SHOW TABLE STATUS FROM 数据库名称 WHERE NAME = '数据表名称';

查看db4数据库中category表的存储引擎

SHOW TABLE STATUS FROM db4 WHERE NAME = 'category';
创建数据表指定存储引擎
CREATE TABLE 表名(
      列名,数据类型,
      ...
)ENGINE = 引擎名称;
CREATE TABLE engine_test(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10)
)ENGINE = MYISAM;

SHOW TABLE STATUS FROM db4;
修改数据表的存储引擎
ALTER TABLE 表名 ENGINE = 引擎名称;

修改engine_test表的存储引擎为InnoDB

ALTER TABLE engine_test ENGINE = INNODB;

存储引擎的选择

MylSAM
特点:不支持事务和外键操作。读取速度快,节约资源。
使用场景:以查询操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高!

InnoDB
特点: MySQL的默认存储引擎,支持事务和外键操作。
使用场景:对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,读写频繁的操作!

MEMORY
特点:将所有数据保存在内存中,在需要快速定位记录和其他类似数据环境下,可以提供更快的访问。
使用场景:通常用于更新不太频繁的小表,用来快速得到访问的结果!

在这里插入图片描述

总结:针对不同的需求场景,来选择最适合的存储引|擎即可!如果不确定、则使用数据库默认的存储引擎!

索引

MySQL索引是帮助MySQL高效获取数据的一种数据结构。所以,索引的本质就是数据结构! 在表数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

索引分类:

普通索引:最基本的索引,没有任何限制。
唯一索引:索引列的值必须唯一,但允许有空值。 如果是组合索引,则列值组合必须唯一。
主键索引: 一种特殊的唯一索引,不允许有空值。在建表时有主键列同时创建主键索引。
联合索引:顾名思义,就是将单列索引进行组合。
外键索引:只有InnoDB引擎支持外键索引,用来保证数据的一致性、完整性和实现级联操作。
全文索引:快速匹配全部文档的方式。InnoDB 引擎5.6版本后才支持全文索引。MEMORY 引擎不支持。

数据准备
-- 创建db9数据库
CREATE DATABASE db9;

-- 使用db9数据库
USE db9;

-- 创建student表
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	age INT,
	score INT
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,98),(NULL,'李四',24,95),
(NULL,'王五',25,96),(NULL,'赵六',26,94),(NULL,'周七',27,99);

创建索引

CREATE [UNIQUE|FULLTEXT] INDEX 索引名称
[USING 索引类型]  -- 默认是BTREE
ON 表名(列名...);

为student表中的name列创建一个普通索引

CREATE INDEX idx_name ON student(NAME); 

为student表中的age列创建一个唯一索引

CREATE UNIQUE INDEX idx_age ON student(age);

查询索引

SHOW INDEX FROM 表名;

查询student表中的索引 (主键列自带主键索引)

SHOW INDEX FROM student;

查询db4数据库中的product表 (外键列自带外键索引)

SHOW INDEX FROM product;

添加索引

ALTER添加索引
-- 普通索引
ALTER TABLE 表名 ADD INDEX 索引名称(列名);

-- 组合索引
ALTER TABLE 表名 ADD INDEX 索引名称(列名1,列名2,...);

-- 主键索引
ALTER TABLE 表名 ADD PRIMARY KEY(主键列名); 

-- 外键索引(添加外键约束,就是外键索引)
ALTER TABLE 表名 
ADD CONSTRAINT 外键名 
FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);

-- 唯一索引
ALTER TABLE 表名 ADD UNIQUE 索引名称(列名);

-- 全文索引
ALTER TABLE 表名 ADD FULLTEXT 索引名称(列名);

为student表中score列添加唯一索引

ALTER TABLE student ADD UNIQUE idx_score(score);

查询student表的索引

SHOW INDEX FROM student;

锁机制

数据库为了保证数据的一致性,在共享的资源被并发访问时变得安全所设计的一种规则。锁机制类似多线程中的同步,作用是可以保证数据的一致性和安全性。

锁的分类

按操作分类
共享锁:针对同一份数据,多个事务读取操作可以同时加锁而互不影响,但是不能修改数据。
排他锁:当前的操作没有完成前,会阻断其他操作的读取和写入。

按颗粒度分类
表级锁:会锁定整个表。开销小,加锁快。锁定粒度打大,发生锁冲突概率高,并发度低。不会出现死锁情况。
行级锁:会锁定当前行。开销大,加锁慢。锁定粒度小,发生冲突概率低,并发度高。会出现死锁的情况。

不同存储引擎支持的锁:

存储引擎表锁行锁
InnoDB支持支持
MyISAM支持不支持
MEMORY支持不支持

悲观锁

它对于数据被外界修改的操作保持保守态度,认为数据随时会修改(悲观)。整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系型数据库提供的锁机制。之前所了解的锁都是悲观锁。

乐观锁

每次自己操作数据的时候认为没有人会来修改它,所以不去加锁(乐观)。但是在更新的时候会判断在此期间数据有没有被修改。需要用户自己去实现,不会发生并抢占资源,只有在提交操作的时候检查是否违法数据完整性。

举报

相关推荐

0 条评论