表与表之间的关系
- ⼀对⼀关系:
- 在实际的开发中应⽤不多.因为⼀对⼀可以创建成⼀张表.
- 常⻅实例:身份证表与员⼯信息表
- ⼀对多关系:
- 常⻅实例:客户和订单,分类和商品,部⻔和员⼯, 省份和城市
- 多对多关系:
- 常⻅实例:学⽣和课程、⽤户和⻆⾊, 演员和电影, 商品和订单
外键约束
现在我们有tb_student和tb_score两张表,为了表明是哪个学生,我们添加id⼀列,⽤于存放学号信息,此列称为:外键
此时“学生表tb_student称为:主表,“id”我们称为主键。得分表tb_score称为:从表,stu_id称为外键。我们通过主表的主键和从表的外键来描述主外键关系,就这让表与表之间产⽣了关系。
- 外键特点:
- 从表外键的值是对主表主键的引⽤。
- 从表外键类型,必须与主表主键类型⼀致。
- 声明外键约束
- 语法:
alter table 从表 add [constraint][外键名称] foreign key (从表外键字段名) references 主表 (主表的主键);
- [外键名称]⽤于删除外键约束的,⼀般建议“_fk”结尾
alter table 从表 drop foreign key 外键名称
使⽤外键⽬的:
- 保证数据完整性
- 要考虑从表添加数据
- 要考虑主键删除数据
提供表结构如下:
# 分类表
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)
);
初始化数据
#分类
INSERT INTO category(cid,cname) VALUES('c001','家电');
INSERT INTO category(cid,cname) VALUES('c002','服饰');
INSERT INTO category(cid,cname) VALUES('c003','化妆品');
#商品
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','雷神',5000,'1','c001');
INSERT INTO products (pid, pname,price,flag,category_id)
VALUES('p004','JACK JONES',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','花花公⼦',440,'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');
多表关系实战
实战1:省和市
- ⽅案1:多张表,⼀对多
-- 创建省份表
create table province(
pid int PRIMARY KEY,
pname varchar(32), -- 省份名称
description varchar(100) -- 描述
);
-- 创建城市表
create table city (
cid int PRIMARY KEY,
cname varchar(32), -- 城市名称
description varchar(100), -- 描述
province_id int,
CONSTRAINT city_province_fk foreign key(province_id) references province(pid)
);
- ⽅案2:⼀张表,⾃关联⼀对多
create table area (
id int PRIMARY key AUTO_INCREMENT,
`name` varchar(32),
description varchar(100),
parent_id int,
CONSTRAINT area_area_fk FOREIGN KEY(parent_id) REFERENCES area(id)
);
INSERT into area values(null, '辽宁省', '这是⼀个省份', null);
INSERT into area values(null, '⼤连市', '这是⼀个城市', 1);
INSERT into area values(null, '沈阳市', '这是⼀个城市', 1);
INSERT into area values(null, '河北省', '这是⼀个省份', null);
INSERT into area values(null, '⽯家庄市', '这是⼀个城市', 4);
INSERT into area values(null, '保定市', '这是⼀个城市', 4);
扫描二维码关注公众号,回复:
11498335 查看本文章
![](/qrcode.jpg)
实战2:用户和角色
- 多对多关系
-- ⽤户表
create table `user` (
uid varchar(32) PRIMARY KEY,
username varchar(32),
`password` varchar(32)
);
-- ⻆⾊表
create table role (
rid varchar(32) PRIMARY KEY,
rname varchar(32)
);
-- 中间表
create table user_role(
user_id varchar(32),
role_id varchar(32),
CONSTRAINT user_role_pk PRIMARY KEY(user_id,role_id),
CONSTRAINT user_id_fk FOREIGN KEY(user_id) REFERENCES `user`(uid),
CONSTRAINT role_id_fk FOREIGN KEY(role_id) REFERENCES role(rid)
);
多表查询(商品有好多分类,但都对应一个分类表)
# 分类表
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),
CONSTRAINT products_category_fk 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 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','雷神',5000,'1','c001');
INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p004','JACK JONES',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','花花公⼦',440,'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 A,B;
select * from category,products ORDER BY cid, pid;
效果: category表中每条记录, 与 products表中每条记录分别连接
常⽤的多表查询⽅式(SQL JOINS 深色区域为查询结果集):
内连接查询(使⽤的关键字 inner join -- inner可以省略)
-
隐式内连接: select * from A,B where 条件;
-
显示内连接: select * from A inner join B on 条件;
-- 查询那些分类的商品已经上架
-- 隐式内连接
SELECT DISTINCT
*
FROM
category c,
products p
WHERE
c.cid = p.category_id;
-- 显示内连接
SELECT DISTINCT
*
FROM
category c INNER JOIN products p
ON
c.cid = p.category_id;
外连接查询(使⽤的关键字 outer join -- outer可以省略)
-
左外连接:left outer join
-
select * from A left outer join B on 条件;
-
-
右外连接:right outer join
-
select * from A right outer join B on 条件;
-
#2.查询所有分类商品的个数
#左外连接
INSERT INTO category(cid,cname) VALUES('c004','奢侈品');
SELECT cname,COUNT(category_id)
FROM category c LEFT OUTER JOIN products p
ON c.cid = p.category_id
GROUP BY cname;
子查询
⼦查询:
⼀条select语句结果作为另⼀条select语法⼀部分(查询条件,查询结果,表等)。
语法:
select ....查询字段 ... from ... 表.. where ... 查询条件
-- ⼦查询, 查询“化妆品”分类上架商品详情
-- 内连接⽅式
select
p.*
from
category c, products p
WHERE
c.cid = p.category_id and c.cname = '化妆品'
-- ⼦查询⽅式 第⼀种(作为查询条件值使⽤)
select
*
from
products p
where
p.category_id = (SELECT cid from category where cname='化妆品')
-- ⼦查询⽅式 第⼆种(作为 ⼀张表 使⽤)
select
p.*
FROM
products p, (select * from category where cname='化妆品') c
WHERE
p.category_id = c.cid;
练习:
#查询“化妆品”和“家电”两个分类上架商品详情
select
*
from
products
WHERE
category_id in (select cid from category where cname='家电' or
cname='化妆品');
-- select cid from category where cname='家电' or cname='化妆品';
-- select cid from category where cname in ('家电', '化妆品');