壬戌之秋,七月既望。眼看就要七月了,回首六月,好像离预期的目标还是太远。大规模仿真实验还在跑跑跑,参数还在调调调,糟心之余,唯一欣慰的是,总共完成了十篇博客,涵盖MySQL和机器学习。本次主要是总结MySQL中的联结组合查询

文章目录

  • 一、联结表
    • 1.创建联结
    • 2.内部联结
    • 3.联结多个表
  • 二、创建高级联结
    • 1.使用表别名
    • 2.使用不同类型的联结
    • 3.使用带聚集函数的联结
  • 三、组合查询
    • 1.创建组合查询
    • 2.使用UNION
  • 四、经典面试题

一、联结表

在阐述联结这个词之前我们先了解一些概念:
关系表
举个例子,这里有一个包含产品目录的数据库,

prod_id—产品编号
vend_id—供应商编号
prod_name—产品名称
prod_price—产品价格
prod_desc—产品描述

如果同一供应商生产多种物品,那么如何储存供应商消息?
一般的,我们会重新创建一个表格,来储存供应商的信息。因为可能会有多个产品对应同一供应商,如果放在同一表格的话,会造成数据重复。如果放在不同的表格,一旦供应商信息发生改变,只需要修改一次即可。
因此,我们为供应商单独建立了一个表格,

在关系型数据库中,各个表通过某一字段关联。Products表只储存产品信息,包括了供应商ID,vend_id表的主键又叫products的外键,它将products表和vendors关联起来。
外键:外键为某一个表的一个字段,同时又为另一个表的主键。
为什么要使用联结?
前面我们讲了,关系型数据库中多个表通过某一字段关联,这样更方便处理,更有效率。但问题是如果数据储存在多个表中,怎么样用单条SELECT语句把我们想要的数据检索出来呢?使用联结可以解决这个问题。联结是一种机制,用来在一条SELECT语句中关联表。

1.创建联结

创建一个联结,返回供应商名称以及提供的产品,

SELECT  vend_name,prod_name,prod_price
FROM    vendors,products
WHERE   vendors.vend_id = products.vend_id;

结果:

在联结两个表时,第一个表的每一行与第二个表的每一行配对。WHERE子句作为过滤条件,它只包含那些匹配给定条件的行。如果没有WHERE子句,第一个表格的每一行会与第二个表格的每一行配对。

2.内部联结

我们之前在WHERE子句中所使用的联结用等号连接,称为等值联结,它基于两个表格的相等测试。这种联结也叫内部联结

SELECT  vend_name,prod_name,prod_price
FROM    vendors INNER JOIN products
ON   vendors.vend_id = products.vend_id;

结果:

3.联结多个表

一条SELECT语句可以联结多个表,数目没有限制,创建表的规则相同。

SELECT  prod_name,vend_name,prod_name,quantity
FROM    products a,vendors b,orderitems c
WHERE   a.vend_id = b.vend_id AND a.prod_id = c.prod_id AND order_num = 20005;

结果:

在第十四章中,我们要列出订购物品TNT2的所有客户,之前使用的是子查询,由内到外依次展开,

SELECT   cust_name,cust_contact
FROM     customers
WHERE    cust_id  IN  (SELECT  cust_idFROM    ordersWHERE   order_num  IN  (SELECT  order_numFROM    orderitemsWHERE   prod_id = 'TNT2'));

这里使用联结,其中WHERE子句中包含三个条件,前两个关联联结中的表,后一个是过滤产品ID为TNT2的数据。

SELECT   cust_name,cust_contact
FROM     orderitems a,orders b,customers c
WHERE    a.order_num = b.order_num  AND b.cust_id = c.cust_id AND a.prod_id ='TNT2';

结果:

二、创建高级联结

除了内联结以外,还有其他的联结类型。

1.使用表别名

为了缩短SQL语句,允许在单条SELECT语句中多次使用相同的表,我们使用别名。别名除了用于列名和计算字段之外,还可以用于表。其实前面我们已经使用过。

SELECT   cust_name,cust_contactFROM     orderitems a,orders b,customers cWHERE    a.order_num = b.order_num  AND b.cust_id = c.cust_id AND a.prod_id ='TNT2';

我们给三个表格分别取名a,b,c,在where子句里,我们就可以使用这些别名,而不用写全称。

2.使用不同类型的联结

前面我们在select语句中使用过内部联结(等值联结),这里再介绍三种联结方式
1)自联结
问题背景:假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也有问题。
第一种方式:使用子查询

SELECT   prod_id,prod_nameFROM     productsWHERE    vend_id  IN(SELECT vend_id FROM   productsWHERE  prod_id = 'DTNTR');

结果:

第二种方式:使用自联结

SELECT   b.prod_id ,b.prod_name
FROM     products a,products b
WHERE    a.vend_id = b.vend_id AND a.prod_id = 'DTNTR';

结果相同,不再展示。使用的两个表是同一个表,实际上是同一个表使用了两次。

2)自然联结
自然联结其实和内部联结一样,只是不会出现相同的重复列。

SELECT  c.*,o.order_num,o.order_date,oi.prod_id,oi.quantity,Oi.item_price
FROM    customers AS  c,orders AS o,orderitems AS oi
WHERE   c.cust_id = o.cust_id AND oi.order_num = o.order_num AND  prod_id = 'FB';

结果:

字体太小,但我们可以发现,没有重复的列出现。
而如果你直接使用内部联结,

SELECT  *
FROM    vendors INNER JOIN products
ON   vendors.vend_id = products.vend_id;

结果:

可以发现,内部联结把将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结。这里就是把 id 相等的部分罗列出来。
3)外部联结
外部联结包含了在联结表中没有关联行的行,比如

  • 对每个客户下了多少订单进行计数,包括哪些没有下订单的客户;
  • 列出所有产品以及订购数量,包括没有被订购的产品;

外部联结包括左联结(left outer join on)和右联结(right outer join on)。
我们把内部联结和外部联结对比一下这里是查询顾客对应的订单:
内部联结:
SELECT a.cust_id,order_num
FROM customers a INNER JOIN orders b
ON a.cust_id = b.cust_id;
结果:

外部联结:

SELECT  a.cust_id,order_num
FROM    customers a LEFT OUTER JOIN orders b
ON      a.cust_id = b.cust_id;

结果:

从这两个结果,我们可以发现,内部联结表把两个表中符合id相等的行取出来,而外部联结中,左边的行一定会列出,右边的表中如果没有匹配的行,则列值为Null。特别需要注意的是如果右表有多行和左表匹配,那么左表相同的行会出现多次。

3.使用带聚集函数的联结

之前的聚集函数只是在一个表中进行汇集数据。如果在多个表中汇集数据,需要使用联结。
比如,要检索所有客户以及每个客户下的订单数,

SELECT  cust_name,c.cust_id,COUNT(*) AS order_num
FROM    orders o INNER JOIN customers c
ON   o.cust_id = c.cust_id
GROUP BY  o.cust_id;

结果:

如果要包含那些没有下订单的顾客,

SELECT  cust_name,c.cust_id,COUNT(order_num) AS order_num
FROM    orders o RIGHT OUTER JOIN  customers c
ON   o.cust_id = c.cust_id
GROUP BY  c.cust_id;

结果:

注意:

  • 不要忘记提供联结条件,否则会得出笛卡尔积;
  • 一个联结中可以包含多个表,每个联结可以包含不同的联结类型。在一起测试这些联结之前,应该分别测试每个联结,利于排除故障。

三、组合查询

之前我们所做的大部分查询都是包含从一个或多个表中返回查询结果的单条SELECT语句。MySQL允许多个查询(多条SELECT语句),并将结果作为单个查询结果返回。这些组合查询也被称为并-union或复合查询。
适用情况:

  • 在单个查询中从不同的表返回类似结构的数据;
  • 对单个表执行多个查询,按单个查询返回数据。
1.创建组合查询

UNION操作符来组合多条SELECT查询,并将结果组合成单个结果集。
在使用UNION时,只需要在每条select语句之间加上关键字UNION即可。
这里,我们要将两个SELECT语句进行组合,
第一个是检索价格不高于5的物品,

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    prod_price <=5;

结果:

第二个是找出供应商1001和1002生产的所有物品,

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    vend_id  IN (1001,1002);

结果:

我们将这两条语句进行组合,

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    prod_price <=5
UNION
SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    vend_id  IN (1001,1002);

结果:

当然这种比较简单的查询,我们可以只用 WHERE + OR 语句

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    prod_price <=5 OR vend_id  IN (1001,1002);
2.使用UNION

有三条基本规则:

  • UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔
  • UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)
  • 列的数据类型必须兼容:类型不必完全相同

去重

UNION从查询结果集中自动去除了重复的行,如果想返回所有匹配的行,可使用UNION ALL

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    prod_price <=5
UNION ALL
SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    vend_id  IN (1001,1002);

结果:

这里就包括了重复的行。一般地,UNION 几乎完成与多个 where 子句相同的工作。UNION ALLUNION 的一种形式,它完成WHERE子句完成不了的工作。如果确实需要每个条件的匹配行全部出现,则必须使用 UNION ALL而不是 WHERE

组合查询结果排序

单条select语句中的排序用 ORDER BY 排序。在用 UNION组合查询时,只能使用一条 ORDER BY ,它必须出现在最后一条 SELECT 语句之后。对于结果集,不允许用一种方式排序一部分,而又用另一种方式排序另一部分,不允许使用多条ORDER BY 子句。

对之前的组合结果使用ORDER BY 子句

SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    prod_price <=5
UNION ALL
SELECT   vend_id,prod_id,prod_price
FROM     products
WHERE    vend_id  IN (1001,1002)
ORDER BY vend_id,prod_id;

结果:

四、经典面试题

问题描述如下:
为管理岗位业务培训信息,建立三个表格:

  • Stu(Sid,SN,SD,SA)表:学生表
    Sid 表示学号
    SN 表示学员姓名
    SD 表示所属单位
    SA 表示学员年龄

  • Cou(Cid,CN)表:课程表
    Cid 课程编号
    CN 课程名称

  • Sco(Sid,Cid,G)表:分数表
    Sid 表示学号
    Cid 课程编号
    G 学习成绩

具体问题参考SQL脚本

################################################################################################################-- 创建学生表CREATE  TABLE  Stu(Sid  INT NOT NULL  PRIMARY  KEY,   SN   VARCHAR(20),SD   VARCHAR(50),SA   INT)ENGINE = INNODB;
-- 创建课程表
CREATE  TABLE  Cou(Cid   VARCHAR(10)  NOT  NULL  PRIMARY  KEY,CN    VARCHAR(20)
)ENGINE = INNODB;
-- 创建成绩表
CREATE   TABLE Sco(Sid   INT  NOT NULL,Cid   VARCHAR(10)  NOT NULL,G     DECIMAL(5,2),CONSTRAINT  fk_Sid  FOREIGN KEY  (Sid)  REFERENCES  Stu(Sid),CONSTRAINT  fk_Cid  FOREIGN KEY  (Cid)  REFERENCES  Cou(Cid)
)ENGINE = INNODB;
#################################################################################################################-- 填充数据INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019001,'托马斯李','运营',26);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019002,'米高扬','管理',30);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019003,'蝙蝠侠','安防',22);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019004,'李嘉诚','投资',45);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019005,'雷军','开发',34);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019006,'周小川','管理',56);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019007,'陆奇','运营',36);
INSERT  INTO  Stu(Sid,SN,SD,SA)   VALUES(2019008,'普京','安防',67);INSERT  INTO  Cou(Cid,CN)   VALUES('C1','税收基础');
INSERT  INTO  Cou(Cid,CN)   VALUES('C2','金融工程');
INSERT  INTO  Cou(Cid,CN)   VALUES('C3','会计');
INSERT  INTO  Cou(Cid,CN)   VALUES('C4','统计学习方法');
INSERT  INTO  Cou(Cid,CN)   VALUES('C5','大数据');
INSERT  INTO  Cou(Cid,CN)   VALUES('C6','机器学习算法');INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019001,'C2',80);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019002,'C2',78);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019003,'C1',89);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019003,'C5',60);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019004,'C4',90);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C1',87);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C2',75);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C3',80);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C4',90);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C5',86);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019005,'C6',88);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019006,'C1',99);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019006,'C2',61);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C1',62);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C2',78);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C3',77);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C4',69);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C5',98);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019007,'C6',88);
INSERT  INTO  Sco(Sid,Cid,G) VALUES(2019008,'C1',78);
#################################################################################################################-- 一、使用标准SQL嵌套语言查询选修课程名称为“税收基础”的学员学号与姓名SELECT    Sid,SN
FROM      Stu
WHERE     Sid   IN  (SELECT  Sid  FROM    ScoWHERE   Cid  IN  (SELECT  Cid  FROM    Cou WHERE   CN  =  '税收基础'));
-- 二、使用标准SQL嵌套语言查询选修课程编号为“C2”的学员姓名和所属单位SELECT   SN,SD
FROM     Stu
WHERE    Sid   IN  (SELECT  SidFROM    ScoWHERE   Cid = 'C2');
-- 三、使用标准SQL嵌套语言查询选修课程编号为“C5”的学员姓名和所属单位SELECT  SN,SD
FROM    Stu p1 INNER JOIN  Sco  p2
ON      p1.Sid  =  p2.Sid  AND  p2.Cid  =  'C5';
-- 四、使用标准SQ嵌套语言查询选修全部课程的学员姓名和所属单位SELECT  SN,SD
FROM    Stu a ,Sco b
WHERE   a.Sid = b.Sid
GROUP BY  b.Sid
HAVING  COUNT(Cid) =  (SELECT COUNT(Cid)FROM   Cou);
-- 五、查询选修课程的学员人数SELECT   CN,COUNT(Sid)
FROM     Cou s1 INNER JOIN Sco s2
ON       s1.Cid  =  s2.Cid
GROUP BY s2.Cid;
-- 六、查询选修课程超过5门的学员学号和所属单位SELECT   s2.Sid,SD
FROM     Sco s1 INNER JOIN  Stu  s2
ON       s1.Sid  =  s2.Sid
GROUP BY  s1.Sid
HAVING    COUNT(Cid) > 5;

参考资料:
1.《MySQL必知必会》 Ben Forta;
2.sql面试题(学生表_课程表_成绩表_教师表):https://www.cnblogs.com/qixuejia/p/3637735.html

MySQL面试试题(五)相关推荐

  1. 最常问的MySQL面试题集合

    除了基础题部分,本文还收集整理的MySQL面试题还包括如下知识点或题型: MySQL高性能索引 SQL语句 MySQL查询优化 MySQL高扩展高可用 MySQL安全性 问题1:char.varcha ...

  2. 企业面试题|最常问的MySQL面试题集合(二)

    MySQL的关联查询语句 六种关联查询 交叉连接(CROSS JOIN) 内连接(INNER JOIN) 外连接(LEFT JOIN/RIGHT JOIN) 联合查询(UNION与UNION ALL) ...

  3. 【2022最新Java面试宝典】—— MySQL面试题(40道含答案)

    目录 1.MySQL 中有哪几种锁? 2.MySQL 中有哪些不同的表格? 3.简述在MySQL 数据库中 MyISAM 和InnoDB 的区别 4.MySQL 中InnoDB 支持的四种事务隔离级别 ...

  4. linux mysql怎么样_最强Linux和Mysql面试题套餐,让你的面试无懈可击!

    引言: 大家好,我是一菲,在软件测试当中linux 操作系统和Mysql数据库的内容是十分的知识同时也是十分重要的.所以一菲这两天通过查阅资料等其他方式为大家梳理了liunx和Mysql面试题大礼包, ...

  5. 去 BAT 面试,总结了这 55 道 MySQL 面试题

    转载自  去 BAT 面试,总结了这 55 道 MySQL 面试题 1.一张表,里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把Mysql重启,再insert一 ...

  6. 去BAT面试完的Mysql面试题总结(55道)

    转载自  去BAT面试完的Mysql面试题总结(55道,带完整答案) 55道互联网大公司的经典面试题,全部答对月薪5W+没问题. 1.一张表里面有ID自增主键,当insert了17条记录之后,删除了第 ...

  7. mysql和linux的题目_最强Linux和Mysql面试题套餐,让你的面试无懈可击!

    引言: 大家好,我是一菲,在软件测试当中linux 操作系统和Mysql数据库的内容是十分的知识同时也是十分重要的.所以一菲这两天通过查阅资料等其他方式为大家梳理了liunx和Mysql面试题大礼包, ...

  8. 精品MySQL面试题,备战八月99%必问!过不了面试算我的

    整合不易,请留下关注,谢谢! MySQL面试题目录 前言 99%必问的十道题 1. 唯一索引比普通索引快吗, 为什么 2. MySQL由哪些部分组成, 分别用来做什么 3. MySQL查询缓存有什么弊 ...

  9. 【面试宝典】Mysql面试题大全

    mysql面试题大全 1.数据库存储引擎 2.InnoDB(B+树) 3.TokuDB( Fractal Tree-节点带数据) 4.MyIASM 5.Memory 6.InnoDB与MyISAM的区 ...

最新文章

  1. 如何让Spring MVC显示自定义的404 Not Found页面
  2. JS_理解函数参数按值传递
  3. php正则检查QQ,PHP 正则匹配手机号的QQ号
  4. php mongodb 视频教程,燕十八mongodb视频资料分享
  5. 使用npm安装vue项目+使用
  6. linux64 gaussian 16,Gaussian 16 运行与硬件配置参考
  7. putty拷贝服务器文件,Windows下拷贝Linux的文件到本地(Putty)
  8. SLAM 之四元数转欧拉角再理解
  9. 误差反向传播(手把手教你推导如何通过反向传播更新参数)
  10. appfuse上手(选取刘文涛blog)
  11. 百度地图 开启 绘制 功能(画圆)
  12. python 会计分录模板_财务月末结账会计分录
  13. 这届90后女博士,对30岁不屑一顾
  14. 无障碍设计标准中的对比度
  15. 输入两个正整数m和n,输出m到n之间每个整数的自然对数
  16. 凯文·米特尼克被称为世界上“头号电脑黑客”(百度搜索)
  17. 【非原创】完全用Linux工作(上)(r4笔记第86天)
  18. 笔记连载 | Day1数字电路基础篇
  19. 第十一届蓝桥杯第三场软件类省赛 C++ B组 题解
  20. 苹果手机字体大小怎么设置?简单实用,轻松学会

热门文章

  1. 利用Hound快速搭建代码搜索引擎
  2. NLP在线医生(一)
  3. 高考数学试题不等关系与不等式|附习题
  4. mysql程序语句范文_MySQL基本语句
  5. 看看阿里、字节跳动、华为等这些大厂的年终奖都发了多少
  6. 虚拟机ubuntu主机板子三者ping通
  7. 01 A股10个月争取翻10倍实盘操作记录(前言)
  8. python股票基本面分析_股票基本面分析
  9. 《计算机科学与探索》期刊投稿
  10. 间歇性宏图大志,持续性混吃等死...