数据库语法总结(3)——多表联查

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

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。其实方法都是殊途同归的,主要是看大家已知的函数运用是否娴熟,逻辑是否清晰合理。

  • 27
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值