MySQL实战系列 -- 3. SQL多表查询

859 阅读6分钟

学习目标

  • 能够使用内连接进行多表查询
  • 能够使用外连接进行多表查询
  • 能够使用子查询进行多表查询

第一章 表之间的关系

1.1 表与表之间的关系

  • 一对一关系:

    • 在实际的开发中应用不多.因为一对一可以创建成一张表.
    • 常见实例:身份证表与员工信息表
  • 一对多关系:

    • 常见实例:客户和订单,分类和商品,部门和员工, 省份和城市
  • 多对多关系:

    • 常见实例:学生和课程、用户和角色, 演员和电影, 商品和订单

1.2 外键约束

现在我们有两张表“分类表”和“商品表”,为了表明商品属于哪个分类,通常情况下,我们将在商品表上添加一列,用于存放分类cid的信息,此列称为:外键

​ 此时“分类表category”称为:主表,“cid”我们称为主键。“商品表products”称为:从表,category_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');

第二章 多表关系实战

2.1 实战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);

2.2 实战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(1), #是否上架标记为:1表示上架、0表示下架
  category_id VARCHAR(32),
  CONSTRAINT products_category_fk FOREIGN KEY (category_id) REFERENCES category (cid)
);

3.1 初始化数据

#分类
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');

3.2 多表查询

交叉连接查询(开发中不使用-得到的是两个表的乘积) [了解]

  • 语法:select * from A,B;
select * from category,products ORDER BY cid, pid;
  • 效果: category表中每条记录, 与 products表中每条记录分别连接

常用的多表查询方式:

内连接查询(使用的关键字 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;
  • 效果

3.3 子查询

子查询概述

子查询

一条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 ('家电', '化妆品');
  • 效果


作者: 能阅读至此, 注定了我们今生有缘! 我已从事Java教育十多年, 怀着教书育人的情怀, 正在让更多的同学们少走弯路, 改变千万IT人的命运!

欢迎关注我的B站,可观看本文章配套视频~~~ 欢迎关注我的公众号,获取更多资料~~~