数据库语法总结(3)——多表联查-程序员宅基地

技术标签: oracle  postgresql  mysql  数据库  sql  

根据前两篇的基础内容,我们今天开始学习多表联查,喜欢的小伙伴可以收藏关注,我会持续更新修改文章。

1、合并多个行集

例如两张没有关联的表出现在同一个查询结果里,我们在前两张的table新增一张表T_EMP,其中有三个字段EMPID,EMPNAME,EMPAGE。此时我想把T_TEST和T_EMP的两表字段一起查出来

SELECT ID,datas,T_NAME FROM T_TEST 
UNION ALL
SELECT EMPID,EMPNAME,EMPAGE FROM T_EMP;

此时有两个注意点:union all必须要保持两个表中查询的字段类型和顺序一致;union all不会去重。

那如果想要去重的话去掉all直接使用union就可以了,其实写全了就是union distinct,distinct是可以省略的。(但是不推荐哦,因为数据量大效率会慢)

同理,还有单表去重时也尽量不使用distinct,尽量用exists替代distinct

2、合并相关的行(根据一张表的其中一个或多个相同的数据查询另一张表中的数据)

SELECT t.ID,t.datas,t.T_NAME,e.EMPNAME  FROM T_TEST t,T_EMP e
 WHERE t.ID =e.EMPID AND t.ID =2

SELECT t.ID,t.datas,t.T_NAME,e.EMPNAME  
 FROM T_TEST t INNER JOIN T_EMP e on  t.ID =e.EMPID WHERE t.ID =1

扩展:两种都属于内连接的形式,具体用哪种方法根据自身喜爱风格。

其中inner join是取on条件的交集,两表都有结果才会有;

全外连接,全拼full outer join(Mysql不支持,需要用到union连接两表结果)Oracle中有特殊的外连接语法:

full join是取两表并集,两表的结果都查出来,没有的数据为空代替;

--正常用法
SELECT t.ID,t.DATAS ,e.EMPID,e.EMPNAME  FROM T_TEST t  FULL JOIN T_EMP e ON
 t.ID =e.EMPID ORDER BY t.ID ;
--Oracle中特殊用法
 SELECT t.ID,t.DATAS,e.EMPID ,e.EMPNAME   FROM T_TEST t,T_EMP e WHERE t.ID =e.EMPID (+)
 UNION
 SELECT t.ID,t.DATAS,e.EMPID ,e.EMPNAME  FROM T_TEST t,T_EMP e WHERE t.ID(+) =e.EMPID ;

还有反连接(anti_join):全写法是left/right outer join,outer可以省略写

left join 以左边表为基准,左表有就显示数据,左表没有就不显示数值,以NULL代替;

right join 以右表为基准,和left join相反。

多提一下:如果多个表想要保留不同数据,可以内连接和反连接同时作用;或者使用子查询,即:

 SELECT a.id,b.name,(SELECT c.age FROM table_c WHERE c.id=b.id) AS age
 FROM table_a a,table_b b WHERE a.id=b.id;

select a.id,b.name,c.age from table_a a 
 inner join table_b b on a.id=b.id 
 left join table_c c on b.id=c.id;

此时select c.age 这的子查询只能查询一个字段,想要进行多字段的子查询,解决方法会在后续具体提到,可以使用对象类型来解决。更新文章之后会附上连接

 针对于上述情况,我们还可以用集合运算  intersect来返回两个表的交集

SELECT EMPID,EMPNAME,EMPAGE  FROM T_EMP 
INTERSECT
SELECT ID,DATAS,t_name  FROM T_TEST;

--两表连接借用in
SELECT EMPID,EMPNAME,EMPAGE  FROM T_EMP 
WHERE (EMPID) IN 
(
    SELECT EMPID  FROM T_EMP 
    INTERSECT
    SELECT ID  FROM T_TEST
);

  扩展:intersect中会返回两个表中相同的行,在此时我们如果只想通过一个关联字段而查询一张表的全部行,则可以借助关键字in

集合运算默认去重,不会返回重复的行。用法类似于union distinct,功能类似于inner join。

3、检索一张表没有出现在另一张表中的数据

与上面集合运算相反,如果我们想要检索在第一张表中出现的数据,而没有在第二章表中出现的数据时,则出现了对应的差集运算。但是在不同类型数据库中差集运算的关键字不同,我们逐一说一下吧:

DB2、PostgreSQL、Sqlserver:使用关键字except

SELECT EMPID,EMPNAME,EMPAGE  FROM T_EMP 
except
SELECT ID,DATAS,t_name  FROM T_TEST 

Oracle中使用关键字minus

SELECT EMPID,EMPNAME,EMPAGE  FROM T_EMP 
minus
SELECT ID,DATAS,t_name  FROM T_TEST 

Mysql中没有差集运算这一关键字,所以我们可以考虑用字段 not in 来查询

SELECT ID,DATAS,t_name  FROM T_TEST  WHERE ID NOT  IN (SELECT EMPID FROM T_EMP);

但是此时我们又遇到了一个问题就是当T_EMP的EMPID字段有NULL值时,则不会有查询结果,因为从本质来说in或not in都是or运算,由于数据库中逻辑运算方式导致的。此时我们扩展一下关于or、and、not在数据库中的逻辑处理(此处是自我理解,有补充的可以留言)

or:有真则为真,T+F=T,T+T=T,T+N=T,相反全假则为假:F+F=F,而N位于T和F之间的位置N+F=N,N+N=N,N+T=T。总结一下就是T>N>F。

and:有假则为假:F+T=F,F+N=F,F+F=F;  同样是全真则为真:T+T=T,而N同样是在两者之间N+T=T,N+N=N,N+F=F。总结一下就是F>N>T

not:很简单,就是取反T<——>F;F<——>T;N<——>N。   

为了避免上述not in的情况我们可以使用关联子查询 not exists

(关联子查询含义:在子查询中引用了外部查询返回的行)

--select 1 代表查询表中任意一行有值数据
SELECT ID,DATAS,t_name  FROM T_TEST t  WHERE  NOT EXISTS
(SELECT 1  FROM T_EMP e WHERE t.ID=e.EMPID);
--或
SELECT ID,DATAS,t_name  FROM T_TEST t  WHERE  NOT EXISTS
(SELECT e.EMPID  FROM T_EMP e WHERE t.ID=e.EMPID);
select 1 from mytable;与select anycol(目的表集合中的任意一行) from mytable;与select * from mytable 作用上来说是没有差别的,都是查看是否有记录,一般是作条件用的。select 1 from 中的1是一常量,查到的所有行的值都是它,但从效率上来说,1>anycol>*,因为不用查字典表。

4、查询两张表中字段不相同的数据或者数量不相同的数据。(就是查询结构相同的两张表中不相同的数据)

此处只提供思路,具体代码就不详细描写了。根据上面3提到的内容,如果我们有两张类似的表想要查看两张表中不同的数据(包括数量,某一字段的数值等等,只要有一个地方不同就列出来,但是如果数量重复还要除重)

这里呢我关注了其他博主的文章;连接如下:

原文链接:https://blog.csdn.net/m0_67621290/article/details/128934531

小伙伴们具体详读就很好理解了!!!

就是使用差集运算算出两表之间不同的字段,然后使用union all连接,但是Mysql和Sqlserver略有不同,使用上述的关联子查询来查找数据然后用union all连接。

扩展:我们在查询数据的时候需要避免笛卡尔积,笛卡尔积又叫笛卡尔乘积,是一个名叫笛卡尔的人提出来的,简单的说就是两个集合相乘的结果,具体有兴趣的小伙伴可以查一下,类似于集合A{a1,a2,a3}三个数,集合B{b1,b2}两个数。然后他们的笛卡尔积就是A*B={(a1,b1),(a1,b2),(a2,b1),(a2,b2),(a3,b1),(a3,b2)}共2*3=6个结果。

避免笛卡尔积就是说要考虑至少需要n-1次连接,此处n是from子句中表的个数。说白话,就是多表联查就首先考虑字段联查,避免出现冗余数据。此处是联查考虑的事前逻辑。

笛卡尔积关键字cross join,用法同inner join不同,cross join不需要on,不用内连接

如果inner join的on条件是1=1,就会有cross join效果,例如:select * from table1 t inner join table2 e on1=1

顺便提一下还有natural join,自然连接相当于=,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。也不用on,不用内连接,但是会除重,作用是内连接。

下面是其他博主的例子,写的很详细,大家可以去看看

https://www.cnblogs.com/klb561/p/11657943.html

5、聚合函数与内/外连接同时使用

聚合函数:是在数据查找基础上对数据的进一步整理筛选行为,常见的聚合函数有:

avg(),max(),min(),sum(),count(),stdev(),stdevp()等等。

(1)同时使用内连接和聚合:

我们在用内连接时,会遇到条件相等时的数据,返回返回多行的情况,如图:执行下面的语句会返回ID为4的数据两条,这是因为我们在T_TEST表中有两条同为4的数据,即使T_EMP只有一条,也会产生两条数据

--两种用法相同,任意一种即可: 
SELECT t.ID,t.DATAS ,e.EMPID,e.EMPNAME  FROM T_TEST t  INNER JOIN T_EMP e ON
 t.ID =e.EMPID ORDER BY t.ID ;
 
  SELECT t.ID,t.DATAS ,e.EMPID,e.EMPNAME  FROM T_TEST t ,T_EMP e WHERE 
 t.ID =e.EMPID ORDER BY t.ID; 

如果我们想要计算T_TEST的ID=1+2+3+4+4=14和T_EMP的EMPID=1+2+3+4=10分别的总和,直接聚合计算结果sumenpid的数值不对,因为4也同时计算了两遍

   SELECT sum(t.ID) AS sumid,SUM(e.EMPID) AS sumempid  
FROM T_TEST t ,T_EMP e WHERE t.ID =e.EMPID;

 为了避免上述情况出现,有两种解决方案:一种是在调用聚合函数时使用distince,这样可以避免重复;另一种是在两表连接前先执行聚合,这样可以避免聚合函数重复运算。

我们先介绍第一种distinct:

Mysql、PostgresSQL中:

SELECT sum(t.ID) AS sumid,SUM(DISTINCT e.EMPID) AS sumempid  
 FROM T_TEST t ,T_EMP e WHERE t.ID =e.EMPID;

DB2、Oracle、Sqlserver中支持使用上面Mysql的方法,也可以使用开窗函数sum over:over后面也可以加分组,由于数据原因,我就不加了。

SELECT DISTINCT  x.IDs,x.EMPIDs FROM ( 
SELECT SUM(t.ID)  OVER () AS  IDs ,SUM(DISTINCT e.EMPID) OVER () AS EMPIDs
FROM T_TEST t  INNER JOIN T_EMP e ON
 t.ID =e.EMPID  ) x;

这样就使返回的结果如下:

 第二种先聚合在连接:

所有数据库都可以使用:

SELECT SUM(IDS) ,SUM(EMPIDs) FROM (

SELECT  SUM(t.ID) AS IDs,x.EMPIDs FROM T_TEST t,

(SELECT e.EMPID,SUM(e.EMPID) AS EMPIDs FROM T_EMP e GROUP BY EMPID) x 

 WHERE t.ID =x.EMPID  GROUP BY x.EMPIDs);

这样就解决了

(2)同时使用外连接和聚合:与内连接和聚合的原理相同,即distinct,sum over,先聚合在外连接,只是需要注意外连接用left outer join。其实方法都是殊途同归的,主要是看大家已知的函数运用是否娴熟,逻辑是否清晰合理。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_61746796/article/details/129861415

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search