ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Mysql多表、外键、和数据库设计

2020-12-03 23:34:04  阅读:315  来源: 互联网

标签:category 多表 -- 外键 查询 products Mysql id


Mysql多表、外键、和数据库设计

多表

实际开发中,一个项目通常需要很多张表才能完成。

外键

添加外键约束

/*
	外键约束
		作用:外键约束可以让两表之间产生一个对应关系,从而保证主表数据完整性
	外键
		指的是在从表中与主表的主键对应的字段
	主表和从表
		主表 主键id所在表,一的一方
		从表 外键字段所在的表,多的一方
	添加外键格式
		1.创建表的时候添加外键
		create table 表名(
			字段...
			[constraint] [外键约束名] foreign key (外键字段名) references 主表(主键字段)
		);
*/

-- 创建部门表
-- 一方,主表
CREATE TABLE department(
id INT PRIMARY KEY AUTO_INCREMENT, 
dep_name VARCHAR(30),
dep_location VARCHAR(30)
);

-- 创建员工表,添加外键
CREATE TABLE employee(
	eid INT PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(20),
	age INT,
	dept_id INT,	-- 外键字段 指向主表主键
	-- 添加外键约束
	CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id)
);

-- 添加2个部门
INSERT INTO department VALUES(NULL, '研发部','广州'),(NULL, '销售部', '深圳');
SELECT * FROM department;

-- 正常添加数据 (从表外键 对应主表主键)
INSERT INTO employee (ename, age, dept_id) VALUES ('张百万', 20, 1);
INSERT INTO employee (ename, age, dept_id) VALUES ('赵四', 21, 1);
INSERT INTO employee (ename, age, dept_id) VALUES ('广坤', 20, 1);
INSERT INTO employee (ename, age, dept_id) VALUES ('小斌', 20, 2);
INSERT INTO employee (ename, age, dept_id) VALUES ('艳秋', 22, 2);
INSERT INTO employee (ename, age, dept_id) VALUES ('大玲子', 18, 2);
SELECT * FROM employee;
-- 插入一条有问题的数据 (部门id不存在)
-- Cannot add or update a child row: a foreign key constraint fails
INSERT INTO employee (ename, age, dept_id) VALUES ('错误', 18, 3);

-- 创建表之后添加外键
-- 语法格式 ALTER TABLE 从表 ADD CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id)
ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id);

外键删除

/*
	删除外键约束
		语法格式
			alter table 从表 drop foreign key 外键约束名称
*/

-- 删除employee表外键
ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;

/*
	外键约束注意事项
		1.主表的外键类型必须和主表类型保持一致
		2.添加数据时,应该先添加主表的数据
		3.删除数据时,需先删除从表数据
*/

级联删除

/*
	级联删除
		指的是在删除主表的数据同时,可以删除与之相关的从表中的数据
	语法格式
		on delete cascade
*/

-- 重新创建添加级联操作
CREATE TABLE employee(
eid INT PRIMARY KEY AUTO_INCREMENT,
ename VARCHAR(20),
age INT,
dept_id INT,
CONSTRAINT emp_dept_fk FOREIGN KEY(dept_id) REFERENCES department(id)
-- 添加级联删除
ON DELETE CASCADE
);

多表关系设计

实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系,接下来我们一起学习一下多表关系设计方面的知识

表与表之间的三种关系

一对多关系: 最常见的关系, 学生对班级,员工对部门
多对多关系: 学生与课程, 用户与角色
一对一关系: 使用较少,因为一对一关系可以合成为一张表

一对多关系

例如:班级和学生,部门和员工,客户和订单,分类和商品

建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键

在这里插入图片描述

多对多关系

例如:老师和学生,学生和课程,用户和角色

建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键。

在这里插入图片描述

一对一

在实际的开发中应用不多.因为一对一可以创建成一张表

建表原则:外键唯一 主表的主键和从表的外键(唯一),形成主外键关系,外键唯一 UNIQUE

设计 省&市表

省和市之间的关系是 一对多关系,一个省包含多个市

在这里插入图片描述

#创建省表 (主表,注意: 一定要添加主键约束)
CREATE TABLE province(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
description VARCHAR(20)
);
#创建市表 (从表,注意: 外键类型一定要与主表主键一致)
CREATE TABLE city(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
description VARCHAR(20),
pid INT,
-- 添加外键约束
CONSTRAINT pro_city_fk FOREIGN KEY (pid) REFERENCES province(id)
);

在这里插入图片描述

设计 演员与角色表

演员与角色 是多对多关系, 一个演员可以饰演多个角色, 一个角色同样可以被不同的演员扮演

在这里插入图片描述

#创建演员表
CREATE TABLE actor(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
#创建角色表
CREATE TABLE role(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
#创建中间表
CREATE TABLE actor_role(
-- 中间表自己的主键
id INT PRIMARY KEY AUTO_INCREMENT,
-- 指向actor 表的外键
aid INT,
-- 指向role 表的外键
rid INT
);
-- 为中间表的aid字段,添加外键约束 指向演员表的主键
ALTER TABLE actor_role ADD FOREIGN KEY(aid) REFERENCES actor(id);
-- 为中间表的rid字段, 添加外键约束 指向角色表的主键
ALTER TABLE actor_role ADD FOREIGN KEY(rid) REFERENCES role(id);

在这里插入图片描述

多表查询

数据准备

-- 创建 db3_2 数据库,指定编码
CREATE DATABASE db3_2 CHARACTER SET utf8;

创建分类表与商品表

#分类表 (一方 主表)
CREATE TABLE category (
cid VARCHAR(32) PRIMARY KEY ,
cname VARCHAR(50)
);
#商品表 (多方 从表)
CREATE TABLE products(
pid VARCHAR(32) PRIMARY KEY ,
pname VARCHAR(50),
price INT,
flag VARCHAR(2),   		#是否上架标记为:1表示上架、0表示下架   
category_id VARCHAR(32),
-- 添加外键约束
FOREIGN KEY (category_id) REFERENCES category (cid)
);
#分类数据
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','鞋服');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
INSERT INTO category(cid,cname) VALUES('c004','汽车');
#商品数据
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p001','小米电视机',5000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p002','格力空调',3000,'1','c001');
INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p003','美的冰箱',4500,'1','c001');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p004','篮球鞋',800,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p005','运动裤',200,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p006','T恤',300,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p007','冲锋衣',2000,'1','c002');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p008','神仙水',800,'1','c003');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p009','大宝',200,'1','c003');

笛卡尔积

在这里插入图片描述

/*
	多表查询语法
		select 字段名称 from 表名
*/

-- 笛卡儿积
-- 多表查询 交叉连接查询
SELECT * FROM products,category;

内连接

/*
	内连接查询
		特点 通过指定条件去匹配两张表中内容,匹配不上不显示
		
		隐式内连接
			语法格式 :select 字段名... from 左表,右表 where 连接条件
		显式内连接
			语法格式: select 字段名... from 左表 join 右表 on 连接条件
*/

-- 查询所有商品信息和对应的分类信息
SELECT * FROM products,category WHERE category_id = cid;

-- 查询商品表的商品名称 和 价格,以及商品的分类信息
SELECT p.pname,p.price,c.cname FROM products p,category c WHERE p.category_id = c.cid;

-- 查询 格力空调是属于哪一分类下的商品
SELECT p.pname,c.cname FROM products p,category c WHERE p.category_id = c.cid AND p.pname = '格力空调';
SELECT p.pname,c.cname FROM products p,category c WHERE p.category_id = c.cid AND p.pid = 'p002';

--  查询所有商品信息和对应的分类信息、
SELECT * FROM products p JOIN category c ON p.category_id = c.cid;

--  查询鞋服分类下,价格大于500的商品名称和价格
SELECT p.pname,p.price FROM products p JOIN category c ON p.category_id = c.cid AND p.price > 500 AND c.cname = '鞋服';

外连接

/*
	外连接
		左外连接
			语法格式 select 字段名 from 左表 left join 右表 on 连接条件 
			特点
				左表为基准匹配右表中的数据,若能够匹配则显现,若匹配不上左表正常显示,右表显示为null
		右外连接
			语法格式 select 字段名 from 左表 right join 右表 on 连接条件 
			特点
				右表为基准匹配右表中的数据,若能够匹配则显现,若匹配不上右表正常显示,左表显示为null
*/

-- 左外连接
SELECT * FROM products p LEFT JOIN category c ON p.category_id = c.cid 

-- 左外连接, 查询每个分类下的商品个数
SELECT c.cname,COUNT(p.pid) '商品个数' FROM category c LEFT JOIN products p ON c.cid  = p.category_id GROUP BY c.cname;

-- 右外连接查询
SELECT * FROM products p RIGHT JOIN category c ON p.`category_id` = c.`cid`;

三种连接比较

在这里插入图片描述

子查询

/*
	子查询
		一条select语句的结果,作为另一条select的一部分
	  特点
			子查询放在小括号中
			子查询作为父查询的条件使用
		分类
			where 子查询:将子查询结果,作为父查询的比较条件
			from 子查询:将子查询结果作为一张表使用
			exists 子查询:查询结果为单列多行情况下,可以将子查询结果作为父查询的in函数中的条件使用
*/
-- 查询价格最高的商品信息
-- 1.查询出最高的价格
SELECT MAX(price) FROM products;
-- 2.根据最高价格查出商品信息
SELECT * FROM products WHERE price = 5000;
-- 使用一条SQL完成
SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products);


-- 子查询做条件
-- 查询化妆品分类下的 商品名称 商品价格
SELECT p.pname,p.price FROM products p WHERE p.category_id = (SELECT c.cid FROM category c WHERE c.cname = '化妆品');
-- 查询小于平均价格的商品信息
SELECT * FROM products p WHERE p.price < (SELECT AVG(price) FROM products);


-- 子查询作为一张表
-- 语法格式:SELECT 查询字段 FROM (子查询)表别名 WHERE 条件;
-- 查询商品中,价格大于500的商品信息,包括 商品名称 商品价格 商品所属分类名称
-- 注意:子查询的结果作为一张表使用,一定要起一个别名,否则无法访问表中字段
SELECT p.pname,p.price,c.cname FROM products p INNER JOIN (SELECT * FROM category) c ON p.category_id = c.cid WHERE p.price > 500;


-- 子查询结果是单列多行
-- 子查询的结果类似一个数组, 父层查询使用 IN 函数 ,包含子查询的结果
-- 语法格式:SELECT 查询字段 FROM 表 WHERE 字段 IN (子查询);
-- 查询价格小于两千的商品,来自于哪些分类(名称)
## 1.查询小于两千的商品的分类id
SELECT DISTINCT category_id FROM products WHERE price < 2000;
## 2.根据分类id查询分类信息
SELECT * FROM category WHERE cid IN (SELECT DISTINCT category_id FROM products WHERE price < 2000);

-- 查询家电类 与 鞋服类下面的全部商品信息
## 1.获取家电类和鞋服类的分类id
SELECT cid FROM category WHERE cname IN ('家电','鞋服');
## 2.根据分类id查找商品
SELECT * FROM products WHERE category_id IN (SELECT cid FROM category WHERE cname IN ('家电','鞋服'));


/*
	子查询总结
		子查询如果是一个字段(单列),那么就在where后面做条件
		如果是多个字段(多列),就当作一张表使用(起别名)
*/

数据库三范式

概念: 三范式就是设计数据库的规则

规则

为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式
满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF) , 其余范式以此类推。一般说来,数据库只需满足第三范式(3NF)就行了

第一范式 1NF

原子性, 做到列不可拆分
第一范式是最基本的范式。数据库表里面字段都是单一属性的,不可再分, 如果数据表中每个字段都是不可再分的最小数据单元,则满足第一范式

在这里插入图片描述

第二范式 2NF

在第一范式的基础上更进一步,目标是确保表中的每列都和主键相关
一张表只能描述一件事

在这里插入图片描述

第三范式 3NF

消除传递依赖
表的信息,如果能够被推导出来,就不应该单独的设计一个字段来存放

在这里插入图片描述

数据库反三范式

反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能
浪费存储空间,节省查询时间 (以空间换时间)

冗余字段

设计数据库时,某一个字段属于一张表,但它同时出现在另一个或多个表,且完全等同于它在其本来所属表的意义表示,那么这个字段就是一个冗余字段

总结

创建一个关系型数据库设计,我们有两种选择
1,尽量遵循范式理论的规约,尽可能少的冗余字段,让数据库设计看起来精致、优雅、让人心醉。
2,合理的加入冗余字段这个润滑剂,减少join,让数据库执行性能更高更快。

标签:category,多表,--,外键,查询,products,Mysql,id
来源: https://blog.csdn.net/weixin_49741990/article/details/110593553

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有