MySQL-多表查询

准备数据:

use db1;

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

-- 订单表
CREATE TABLE orderList(
  id INT PRIMARY KEY AUTO_INCREMENT,	-- 订单id
  number VARCHAR(30),					-- 订单编号
  uid INT,    -- 外键字段
  CONSTRAINT ou_fk FOREIGN KEY (uid) REFERENCES user(id)
);

-- 添加数据
INSERT INTO orderList VALUES (NULL,'test001',1),(NULL,'test002',1),(NULL,'test003',2),
(NULL,'test004',2),(NULL,'test005',3),(NULL,'test006',3),(NULL,'test007',NULL);


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


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

多表查询:

笛卡尔积:指A表和B表所有组合的情况,在查询数据时需消除笛卡尔积现象

-- 多表查询,笛卡尔积现象
select * from product , category;

-- 消除笛卡尔积现象
select * from product p, category c where p.cid = c.id;

内连接:

内连接查询的是两张表有交集的数据(有主外键关联的数据)

显式内连接

-- 标准语法  INNER可写可不写
SELECT 列名 FROM1 [INNER] JOIN2 ON1.公共字段 =2.公共字段;
-- 查询用户信息和对应的订单信息,起别名
SELECT u.name ,o.number FROM user u JOIN orderList o ON u.id = o.uid;

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

隐式内连接:

-- 标准语法
SELECT 列名 FROM1,2 WHERE 条件 表1.公共字段 =2.公共字段;

-- 隐式内连接查询
-- 查询用户姓名和订单编号
SELECT u.name,o.number FROM USER u, orderList o WHERE u.id=o.uid;

问题:下面这两个语句执行结果是否一致

SELECT u.name ,o.number FROM user u JOIN orderList o ON u.id = o.uid;
SELECT u.name ,o.number FROM orderList o JOIN user u ON u.id = o.uid;

答:一致,因为内连接获取的是两个表的公共部分

外连接:

左外连接:

查询左表的全部数据,和左右两张表有交集部分的数据。

演示:

-- 标准语法   OUTER可写可不写
SELECT 列名 FROM1 LEFT [OUTER] JOIN2 ON1.公共字段 =2.公共字段;

-- 查询所有用户信息,以及用户对应的订单信息
SELECT u.*,o.number FROM USER u LEFT OUTER JOIN orderList o ON u.id = o.uid;

右外连接:

查询右表的全部数据,和左右两张表有交集部分的数据

-- 基本语法   OUTER可写可不写
SELECT 列名 FROM1 RIGHT [OUTER] JOIN2 ON1.公共字段 =2.公共字段;
select 列名 from1 right join2 on1.公共字段=2.公共字段

-- 查询所有订单信息,以及订单所属的用户信息
SELECT u.*,o.* FROM USER u RIGHT OUTER JOIN orderList o ON u.id=o.uid;

右连接也可以变成左连接,所以开发使用左连接比较多

SELECT u.*, o.* FROM orderList o LEFT JOIN USER u ON u.id=o.uid;

自连接:

子连接查询,可以是内连接也可以是外连接查询,也就是自己连接自己。

-- 自连接语法:
select 字段列表 from1 别名1 JOIN1 别名2 ON 别名1.公共字段 = 别名2.公共字段;

-- 创建员工表
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);

-- 查询所有员工的姓名及其直接上级的姓名,
SELECT e1.name, e2.name FROM employee e1,employee e2 WHERE e1.mgr = e2.id;

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

联合查询:

就是把多次查询的结果合并起来,形成一个新的查询结果集。

对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致,UNION ALL会将全部的数据直接合并在一起,UNION会把合并后的数据去重

-- 语法
-- SELECT 字段列表 FROM 表A UNION [ALL] SELECT 字段列表 FROM 表B;
-- 查询薪资大于5000,年龄大于50的员工
select * from user  where age > 20;
select * from user  where salary > 5000;

-- 把这两个语句连接起来就是联合查询
select * from user  where age > 20 union all select * from user  where salary > 5000;

-- 去重
select * from user  where age > 20 union select * from user  where salary > 5000;

子查询:

  • SQL语句中嵌套了SELECT语句,称为嵌套查询或子查询。

子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任意一个

根据查询结果不同,子查询分为:

  • 标量子查询(子查询结果为单个值)
  • 列子查询(子查询结果为一列)
  • 行子查询(子查询结果为一行)
  • 表子查询(子查询结果为多行多列)

标量子查询:

子查询返回的结果是单个值(数字、字符串、日期等),这种查询称为标量子查询。

常用的操作符:=、<>、>、 >=、<、<=

演示:

-- 查询手机数码分类下的所有商品信息,先查询到分类id,再用分类id查询所有商品
select id from category where name = '手机数码';
select * from product where cid = 1;

-- 使用标量子查询实现
select * from product where cid = (select id from category where name = '手机数码');

列子查询:

子查询的返回结果是一列(可以是多行),这种子查询称为列子查询

常用的操作符:IN、NOT IN、ANY、SOME、ALL

操作符含义
IN在指定的集合范围之内,多选一
NOT IN不在指定的集合范围之内
ANY子查询返回列表中,有任意一个满足即可
SOME子ANY等同,使用SOME的地方都可以使用ANY
ALL子查询返回列表的所有值都必须满足

演示:

-- 查询"手机数码"分类下的所有商品价格,先查id
select id from category where name = '手机数码';

-- 再查分类下所有的商品价格
select price from product where cid = (select id from category where name = '手机数码');

-- 查询比"手机数码"全部商品价都要高的商品信息(总和)
select * from product where price > all (select price from product where cid = (select id from category where name = '手机数码'));

-- 查询比"手机数码"分类下任意一个价格高的商品信息,使用any和some一样
select * from product where price > any (select price from product where cid = (select id from category where name = '手机数码'));

行子查询:

子查询的返回结果是一行(可以是多列),这种子查询称为行子查询。

常用的操作符:=、<>、IN、NOT IN

-- 查询"华为手机"的价格及所属分类下相同价格的商品信息,先查华为手机的所属分类
select cid from product where name ='华为手机';

-- 查询该分类下与华为手机价格相同的商品信息,对比查询结果即可
select * from product where (cid) = (1);

-- 转换成动态的查询结果
select * from product where (cid) = (select cid from product where name ='华为手机');

表子查询:

子查询的返回结果是多行多列,这种子查询称为表子查询

常用的操作符:IN

-- 查询和'华为手机'、'小米手机'的分类、价格相同的商品信息
-- 先查'华为手机'、'小米手机'的分类、价格
select name,price from product where name = '华为手机' or name = '小米手机';

select * from product where (name,price) in(select name,price from product where name = '华为手机' or name = '小米手机');

 -- 查询商品上架时间是'2023-01-01'之后的商品信息及所属分类信息,把结果作为一个表
 select * from product where putawayDate > '2023-01-01';

-- 查询这些商品及分类信息
select p.*,c.* from ( select * from product where putawayDate > '2023-01-01') p left join category c on c.id = p.cid;

多表查询练习:

1、查询用户的id、姓名、年龄、订单编号

/*
分析:
	user用户表:id、姓名、年龄  
	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、查询所有的用、用户的id、姓名、年龄、订单编号

/*
分析:
	user表:id、姓名、年龄  
	orderList表:订单编号
	条件:user.id = orderList.uid
	查询所有用户,使用左外连接
*/

SELECT
	u.id,
	u.NAME,
	u.age,
	o.number 
FROM
	USER u
	LEFT INNER JOIN orderList o ON u.id = o.uid;

3、查询所有的订单、用户的id、姓名、年龄、订单编号

/*
分析:
	user表:id、姓名、年龄 
	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岁的信息、显示用户的id、姓名、年龄、订单编号

/*
分析:
	user表:id、姓名、年龄 
	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、查询张三、李四用户的信息。显示用户的id、姓名、年龄。订单编号

/*
分析:
	user表:id、姓名、年龄 
	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、查询商品分类的id、分类名称、分类下的商品名称

/*
分析:
	category表:商品分类的编号、分类名称
	product表:分类下的商品名称 
	条件:category.id = product.cid
*/

SELECT
	c.id,
	c.NAME,
	p.cid 
FROM
	category c,
	product p 
WHERE
	c.id = p.cid;

7、查询所有的商品分类、商品分类的id、分类名称、分类下的商品名称

/*
分析:
	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、查询所有的商品信息、商品分类的id、分类名称、分类下的商品名称

/*
分析:
	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、查询所有的用户和该用户能查看的所有的商品、显示用户的id、姓名、年龄、商品名称

/*
分析:
	user表:用户的id、姓名、年龄
	us_pro中间表:
	product表:商品名称
	条件: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、查询张三和李四这两个用户可以看到的商品。显示用户的id、姓名、年龄、商品名称

/*
分析:
	user表:用户的id、姓名、年龄
	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 ( '张三', '李四' );
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzhuzhu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值