一、约束
外键约束
外键约束概念
- 让表和表之间产生关系,从而保证数据的准确性!
CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主表主键列名)
-- 创建orderlist订单表
CREATE TABLE orderlist(
id INT PRIMARY KEY AUTO_INCREMENT, -- id
number VARCHAR(20) NOT NULL, -- 订单编号
uid INT, -- 订单所属用户
CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id) -- 添加外键约束
);
-- 标准语法
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
-- 删除外键
ALTER TABLE orderlist DROP FOREIGN KEY ou_fk1;
-- 标准语法
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);
-- 添加外键约束
ALTER TABLE orderlist ADD CONSTRAINT ou_fk1 FOREIGN KEY (uid) REFERENCES USER(id);
外键的级联更新和级联删除
-
什么是级联更新和级联删除
- 当我想把user用户表中的某个用户删掉,我希望该用户所有的订单也随之被删除
- 当我想把user用户表中的某个用户id修改,我希望订单表中该用户所属的订单用户编号也随之修改
-- 添加外键约束,同时添加级联更新 标准语法
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名) ON UPDATE CASCADE;
-- 添加外键约束,同时添加级联删除 标准语法
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名) ON DELETE CASCADE;
-- 添加外键约束,同时添加级联更新和级联删除 标准语法
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名) ON UPDATE CASCADE ON DELETE CASCADE;
-- 删除外键约束
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;
-- 将王五用户的id修改为5 订单表中的uid也随之被修改
UPDATE USER SET id=5 WHERE id=3;
-- 将王五用户删除 订单表中该用户所有订单也随之删除
DELETE FROM USER WHERE id=5;
二、多表设计
一对一
在任意一个表建立外键,去关联另外一个表的主键
-- 创建card表
CREATE TABLE card(
id INT PRIMARY KEY AUTO_INCREMENT,
number VARCHAR(50),
pid INT UNIQUE,
CONSTRAINT cp_fk1 FOREIGN KEY (pid) REFERENCES person(id) -- 添加外键
);
一对多
在多的一方,建立外键约束,来关联一的一方主键
-- 创建product表
CREATE TABLE product(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
cid INT,
CONSTRAINT pc_fk1 FOREIGN KEY (cid) REFERENCES category(id) -- 添加外键约束
);
多对多
需要借助第三张表中间表,中间表至少包含两个列,这两个列作为中间表的外键,分别关联两张表的主键
-- 创建中间表
CREATE TABLE stu_course(
id INT PRIMARY KEY AUTO_INCREMENT,
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) -- 添加外键约束
);
三、多表查询
多表查询-笛卡尔积查询
SELECT
列名列表
FROM
表名列表
WHERE
条件...
-- 标准语法
SELECT 列名 FROM 表名1,表名2,...;
-- 查询user表和orderlist表
SELECT * FROM USER,orderlist;
多表查询-内连接查询
查询原理
- 内连接查询的是两张表有交集的部分数据(有主外键关联的数据)
显式内连接
-- 标准语法
SELECT 列名 FROM 表名1 [INNER] JOIN 表名2 ON 条件;
-- 查询用户信息和对应的订单信息
SELECT * FROM USER INNER JOIN orderlist ON user.id=orderlist.uid;
SELECT * FROM USER JOIN orderlist ON user.id=orderlist.uid;
-- 查询用户信息和对应的订单信息,起别名
SELECT * FROM USER u JOIN orderlist o ON u.id=o.uid;
-- 查询用户姓名,年龄。和订单编号
SELECT
u.`name`, -- 姓名
u.`age`, -- 年龄
o.`number` -- 订单编号
FROM
USER u -- 用户表
JOIN
orderlist o -- 订单表
ON
u.`id` = o.`uid`;
隐式内连接
-- 标准语法
SELECT 列名 FROM 表名1,表名2 WHERE 条件;
-- 查询用户姓名,年龄。和订单编号
SELECT
u.`name`, -- 姓名
u.`age`, -- 年龄
o.`number` -- 订单编号
FROM
USER u, -- 用户表
orderlist o -- 订单表
WHERE
u.`id`=o.`uid`;
多表查询-外连接查询
-
左外连接
- 查询原理
- 查询左表的全部数据,和左右两张表有交集部分的数据
- 查询原理
-- 标准语法
SELECT 列名 FROM 表名1 LEFT [OUTER] JOIN 表名2 ON 条件;
-- 查询所有用户信息,以及用户对应的订单信息
SELECT
u.`name`, -- 姓名
u.`age`, -- 年龄
o.`number` -- 订单编号
FROM
USER u -- 用户表
LEFT OUTER JOIN
orderlist o -- 订单表
ON
u.`id`=o.`uid`;
-
右外连接
- 查询原理
- 查询右表的全部数据,和左右两张表有交集部分的数据
- 查询原理
-- 基本语法
SELECT 列名 FROM 表名1 RIGHT [OUTER] JOIN 表名2 ON 条件;
-- 查询所有订单信息,以及订单所属的用户信息
SELECT
u.`name`, -- 姓名
u.`age`, -- 年龄
o.`number` -- 订单编号
FROM
USER u -- 用户表
RIGHT OUTER JOIN
orderlist o -- 订单表
ON
u.`id`=o.`uid`;
多表查询-子查询
查询语句中嵌套了查询语句。我们就将嵌套查询称为子查询!
子查询-结果是单行单列的
可以作为条件,使用运算符进行判断!
-- 标准语法
SELECT 列名 FROM 表名 WHERE 列名=(SELECT 聚合函数(列名) FROM 表名 [WHERE 条件]);
-- 查询年龄最高的用户姓名
SELECT MAX(age) FROM USER; -- 查询出最高年龄
SELECT NAME,age FROM USER WHERE age=26; -- 根据查询出来的最高年龄,查询姓名和年龄
SELECT NAME,age FROM USER WHERE age = (SELECT MAX(age) FROM USER);
子查询-结果是多行单列的
可以作为条件,使用运算符in或not in进行判断!
-- 标准语法
SELECT 列名 FROM 表名 WHERE 列名 [NOT] IN (SELECT 列名 FROM 表名 [WHERE 条件]);
-- 查询张三和李四的订单信息
SELECT id FROM USER WHERE NAME='张三' OR NAME='李四'; -- 查询张三和李四用户的id
SELECT number,uid FROM orderlist WHERE uid=1 OR uid=2; -- 根据id查询订单
SELECT number,uid FROM orderlist WHERE uid IN (SELECT id FROM USER WHERE NAME='张三' OR NAME='李四');
子查询-结果是多行多列的
可以作为一张虚拟表参与查询!
-- 标准语法
SELECT 列名 FROM 表名 [别名],(SELECT 列名 FROM 表名 [WHERE 条件]) [别名] [WHERE 条件];
-- 查询订单表中id大于4的订单信息和所属用户信息
SELECT * FROM USER u,(SELECT * FROM orderlist WHERE id>4) o WHERE u.id=o.uid;
多表查询练习
- 查询用户的编号、姓名、年龄。订单编号
/*
分析:
用户的编号、姓名、年龄 user表 订单编号 orderlist表
条件:user.id = orderlist.uid
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
FROM
USER t1, -- 用户表
orderlist t2 -- 订单表
WHERE
t1.`id` = t2.`uid`;
- 查询所有的用户。用户的编号、姓名、年龄。订单编号
/*
分析:
用户的编号、姓名、年龄 user表 订单编号 orderlist表
条件:user.id = orderlist.uid
查询所有用户,使用左外连接
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
FROM
USER t1 -- 用户表
LEFT OUTER JOIN
orderlist t2 -- 订单表
ON
t1.`id` = t2.`uid`;
- 查询所有的订单。用户的编号、姓名、年龄。订单编号
/*
分析:
用户的编号、姓名、年龄 user表 订单编号 orderlist表
条件:user.id = orderlist.uid
查询所有订单,使用右外连接
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
FROM
USER t1 -- 用户表
RIGHT OUTER JOIN
orderlist t2 -- 订单表
ON
t1.`id` = t2.`uid`;
- 查询用户年龄大于23岁的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析:
用户的编号、姓名、年龄 user表 订单编号 orderlist表
条件:user.age > 23 AND user.id = orderlist.uid
*/
/*
select
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
from
user t1, -- 用户表
orderlist t2 -- 订单表
where
t1.`age` > 23
and
t1.`id` = t2.`uid`;
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
FROM
USER t1 -- 用户表
LEFT OUTER JOIN
orderlist t2 -- 订单表
ON
t1.`id` = t2.`uid`
WHERE
t1.`age` > 23;
- 查询张三和李四用户的信息。显示用户的编号、姓名、年龄。订单编号
/*
分析:
用户的编号、姓名、年龄 user表 订单编号 orderlist表
条件:user.id = orderlist.uid AND user.name IN ('张三','李四');
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户姓名
t1.`age`, -- 用户年龄
t2.`number` -- 订单编号
FROM
USER t1, -- 用户表
orderlist t2 -- 订单表
WHERE
t1.`id` = t2.`uid`
AND
-- (t1.`name` = '张三' OR t1.`name` = '李四');
t1.`name` IN ('张三','李四');
- 查询商品分类的编号、分类名称。分类下的商品名称
/*
分析:
商品分类的编号、分类名称 category表 分类下的商品名称 product表
条件:category.id = product.cid
*/
SELECT
t1.`id`, -- 分类编号
t1.`name`, -- 分类名称
t2.`name` -- 商品名称
FROM
category t1, -- 商品分类表
product t2 -- 商品表
WHERE
t1.`id` = t2.`cid`;
- 查询所有的商品分类。商品分类的编号、分类名称。分类下的商品名称
/*
分析:
商品分类的编号、分类名称 category表 分类下的商品名称 product表
条件:category.id = product.cid
查询所有的商品分类,使用左外连接
*/
SELECT
t1.`id`, -- 分类编号
t1.`name`, -- 分类名称
t2.`name` -- 商品名称
FROM
category t1 -- 商品分类表
LEFT OUTER JOIN
product t2 -- 商品表
ON
t1.`id` = t2.`cid`;
- 查询所有的商品信息。商品分类的编号、分类名称。分类下的商品名称
/*
分析:
商品分类的编号、分类名称 category表 分类下的商品名称 product表
条件:category.id = product.cid
查询所有的商品信息,使用右外连接
*/
SELECT
t1.`id`, -- 分类编号
t1.`name`, -- 分类名称
t2.`name` -- 商品名称
FROM
category t1 -- 商品分类表
RIGHT OUTER JOIN
product t2 -- 商品表
ON
t1.`id` = t2.`cid`;
- 查询所有的用户和所有的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析:
用户的编号、姓名、年龄 user表 商品名称 product表 中间表 us_pro
条件:us_pro.uid = user.id AND us_pro.pid = product.id
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户名称
t1.`age`, -- 用户年龄
t2.`name` -- 商品名称
FROM
USER t1, -- 用户表
product t2, -- 商品表
us_pro t3 -- 中间表
WHERE
t3.`uid` = t1.`id`
AND
t3.`pid` = t2.`id`;
- 查询张三和李四这两个用户可以看到的商品。显示用户的编号、姓名、年龄。商品名称
/*
分析:
用户的编号、姓名、年龄 user表 商品名称 product表 中间表 us_pro
条件:us_pro.uid = user.id AND us_pro.pid = product.id AND user.name IN ('张三','李四')
*/
SELECT
t1.`id`, -- 用户编号
t1.`name`, -- 用户名称
t1.`age`, -- 用户年龄
t2.`name` -- 商品名称
FROM
USER t1, -- 用户表
product t2, -- 商品表
us_pro t3 -- 中间表
WHERE
(t3.`uid` = t1.`id` AND t3.`pid` = t2.`id`)
AND
-- (t1.`name` = '张三' or t1.`name` = '李四');
t1.`name` IN ('张三','李四');
多表查询-自关联查询
同一张表中有数据关联。可以多次查询这同一个表!
-- 创建员工表
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表
条件:employee.mgr = employee.id
查询左表的全部数据,和左右两张表交集部分数据,使用左外连接
*/
SELECT
t1.name, -- 员工姓名
t1.mgr, -- 上级编号
t2.id, -- 员工编号
t2.name -- 员工姓名
FROM
employee t1 -- 员工表
LEFT OUTER JOIN
employee t2 -- 员工表
ON
t1.mgr = t2.id;
四、视图
概念
- 视图是一种
虚拟存在的数据表
- 这个虚拟的表并不在数据库中实际存在
- 作用是将一些比较复杂的查询语句的结果,封装到一个虚拟表中。后期再有相同复杂查询时,直接查询这张虚拟表即可
- 说白了,
视图就是将一条SELECT查询语句的结果封装到了一个虚拟表中
,所以我们在创建视图的时候,工作重心就要放在这条SELECT查询语句上
好处
简单
对于使用视图的用户不需要关心表的结构、关联条件和筛选条件。因为这张虚拟表中保存的就是已经过滤好条件的结果集
安全
视图可以设置权限 , 致使访问视图的用户只能访问他们被允许查询的结果集
数据独立
一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响
视图数据准备
-- 创建db7数据库
CREATE DATABASE db7;
-- 使用db7数据库
USE db7;
-- 创建country表
CREATE TABLE country(
id INT PRIMARY KEY AUTO_INCREMENT,
country_name VARCHAR(30)
);
-- 添加数据
INSERT INTO country VALUES (NULL,'中国'),(NULL,'美国'),(NULL,'俄罗斯');
-- 创建city表
CREATE TABLE city(
id INT PRIMARY KEY AUTO_INCREMENT,
city_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 查询语句;
-- 普通多表查询,查询城市和所属国家
SELECT
t1.*,
t2.country_name
FROM
city t1,
country t2
WHERE
t1.cid = t2.id;
-- 经常需要查询这样的数据,就可以创建一个视图
-- 创建一个视图。将查询出来的结果保存到这张虚拟表中
CREATE
VIEW
city_country
AS
SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
-- 创建一个视图,指定列名。将查询出来的结果保存到这张虚拟表中
CREATE
VIEW
city_country2 (city_id,city_name,cid,country_name)
AS
SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
视图的查询
-- 标准语法
SELECT * FROM 视图名称;
-- 查询视图。查询这张虚拟表,就等效于查询城市和所属国家
SELECT * FROM city_country;
-- 查询指定列名的视图
SELECT * FROM city_country2;
-- 查询所有数据表,视图也会查询出来
SHOW TABLES;
-- 标准语法
SHOW CREATE VIEW 视图名称;
SHOW CREATE VIEW city_country;
视图的修改
-- 标准语法
UPDATE 视图名称 SET 列名=值 WHERE 条件;
-- 修改视图表中的城市名称北京为北京市
UPDATE city_country SET city_name='北京市' WHERE city_name='北京';
-- 查询视图
SELECT * FROM city_country;
-- 查询city表,北京也修改为了北京市
SELECT * FROM city;
-- 注意:视图表数据修改,会自动修改源表中的数据
-- 标准语法
ALTER VIEW 视图名称 [(列名列表)] AS 查询语句;
-- 查询视图2
SELECT * FROM city_country2;
-- 修改视图2的列名city_id为id
ALTER
VIEW
city_country2 (id,city_name,cid,country_name)
AS
SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;
视图的删除
-- 标准语法
DROP VIEW [IF EXISTS] 视图名称;
-- 删除视图
DROP VIEW city_country;
-- 删除视图2,如果存在则删除
DROP VIEW IF EXISTS city_country2;
五、备份与还原
命令行方式
备份
mysqldump -u root -p 数据库名称 > 文件保存路径\
恢复
登录mysql数据库
删除已经备份的数据库
重新创建名称相同的数据库
使用该数据库
导入文件执行:source 备份文件路径;
图形化界面方式
备份
恢复