百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

常用SQL系列之(三):记录叠加、匹配、外连接及笛卡尔等

sinye56 2024-09-22 08:24 5 浏览 0 评论

本系统为@牛旦教育IT课堂在微头条上的内容,

为便于查阅,特辑录于此,都是常用SQL基本用法。。

前两篇连接:

(一):SQL点滴(查询篇):数据库基础查询案例实战

(二):SQL点滴(排序篇):数据常规排序查询实战示例



(17)如何实现多表记录的叠加返回?


也就是如何将来自多个表的数据组织到一起,把各个表的结果叠加起来。这些表不必要有相同的关键字,但各表对应的列的数据类型应相同。例如我们现实部门编号为2的所有员工的名字和编号,以及部门的名字和编号,实现参考SQL如下:
select ename , emid from employee where departid=2
union all
select '-----------', null
union all
select dpname,dpid from department
中间select横线是可选的 ,以示多表间结果的分立。这样关键的是应用union all来实现多表结果的叠加返回。所以可能有重复的结果。若果想去重,可以结合distinct来对结果应用子查询来处理。

(18)如何基于关联列把不同表列值组合到一行返回?


也就是说通过相关联的列(多为外键),实现把不同表的行列值累加到另一表的行列值作为一行返回(若有多个行符合条件的就会返回多行)。我们以员工和部门为例来实现相关行组合,现实员工姓名、工资、部门名称和地址,SQL示例如下:
select ename,salary,d.dpname,d.dpaddress from employee e,tx_department d where e.departid = d.dpid
其实这是一种数据库关联查询的内连接,是关联列的等值查询。还有一种用inner join写法,参考如下:
select ename,salary,d.dpname,d.dpaddress from employee e inner join tx_department d on e.departid = d.dpid
那可以不等吗?


(19)如何在两个表中查找共同行?


换句话说,就是A表和B表,存在这种情况,即A表中的行值有包含于B表中行值(相当于B表行值的子行)的,比如员工表和团队表,团队表包含人名、工作、部门id,员工表中包含团队表中信息,那如何实现即返回团队的所有信息又返回员工的薪资和编号信息?我们可以这样来写SQL,参考如下:
select e.eid,e.ename,e.job,e.salary,e.departid from employee e ,team t
where e.ename =t.ename and e.job =t.job and e.departid =t.departid
这样,我们就可以实现我们想要的结果了。
当然,你可以参考值我们前面的例子(SQL点滴(18):如何基于关联列把不同表列值组合到一行返回?也就是说通过相关联的列(多为外键),实现把不同表的行列值累...),把上面的语句改成join子句的形式。试试吧。

(20)如何从一个表中查找另一个表中没有的值?


也就是说,从一个(称为数据源)中查找另一个目标表中不存在的值。比如,从部门表department中查找在雇员表employee中不存在数据的所有部门(相当于说,若部门表有10条记录,而雇员表中的部门只用了不到10个的部门,把没有使用的部门找出来)。对于这个问题,不同的DB有不同的解决方法,比如DB2、PostgreSQL、Oracle支持差集操作,而MySQL和SQL Server不支持,因而在MySQL中,我们使用子查询来实现,参考例句如下:
select departid from department where departid not in (select departid from employee)。
此句也适用SQL Server。
那么在,支持差集操作的Oracle中,可以这样实现:
select departid from department
minus
select departid from employee
就能实现我们想要的目的。若是DB2或PostgreSQL,只是差集关键字不一样,用except替换minus即可。但需要注意的是,在except/minus差集操作中,两个select列表中值得数目和数据类型必须匹配,而且except不会返回重复行。含义就是从前一个查询结果中返回所有在后一个查询结果中没有的行。

(21):如何利用外连接在一个表中查找与其它表不匹配的记录?


比如有这样的场景,部门表中用8部门,而员工表中仅仅只关联了6个部门,如何用外连接找出没有员工的部门?我们可以这样干:
select d.* from department d left outer join employee e on (d.departid =e.departid) where e.departid is null 。
这样我们就可以把没有员工的部门全部找出来了。以上SQL适用MySQL、BD2、SQL Server及PostgreSQL。若是Oracle 9i及之后,上述写法也适用。你还可以用Oracle独有的外连接语法(+),比如:select d.* from department d , employee e where d.departid =e.departid (+) and e.departid is null
试试吧。


(22):有3张关联表,如何基于前两表的全关联附加第三张表部分关联信息 ?


场景可以这样描述:部门表和员工表以及员工奖励表,那么要返回所有员工姓名和所在部门,并关联显示部分受到奖励的员工奖励日期(不是所有员工都得到奖励的,少数几个吧)。我们可以这样来写SQL语句:
SELECT
e.ename ,d.dpname,b.received
FROM
employee e JOIN department d
ON ( e.departid = d.dpid )
left join ebonus b
on (e.emid = b.emid)
order by 2
结果见下图。顺便一提:如果只返回有奖励的员工的上述信息,这个SQL语句怎么改写?动手试试吧^_^


(23):多表查询时笛卡儿积及处理规则是怎样的?



场景如下,部门表中有4条记录,员工表中有部门2的记录是3条,如果我们这样查询,就会产生笛卡儿积:
SELECT
e.empname,
d.dpname
FROM
employee e,
depart d
WHERE
e.dpid = 2
ORDER BY 1
结果会返回12条记录,这显然不合期望,由于笛卡尔积出现了。
这里产生笛卡尔积的原因类似于从A地经B地到达C地,分为2段走法,A到B有3中走法,B到C有4种走法,那最终A到C就有3*4=12中方法,这在表中查询如按照这种不受约束的执行,就产生了笛卡尔积。所以,一般来说,要避免笛卡尔积,需要使用n-1规则,n为from后表的数量,n-1是避免产生笛卡尔积的最小连接数。根据表中中的关键字和关联列不同,可能需要超过n-1的个连接。如何改正上面的SQL语句以避免笛卡尔积?按规则,可以这样来:
SELECT
e.empname,
d.dpname
FROM employee e,depart d
WHERE e.dpid = 2 and e.dpid = d.dpid
ORDER BY 2
这样就可以了。试试看吧,关键是理解上面的规则。


(24):聚集于外连接时的重复计算问题


场景是这样的,即统计部门2(主键值)中的员工的工资总额和奖金总额。这里假设每位员工的工资都是固定的,但可以有多次奖励记录,假设abc员工有两次奖励记录,我们第一次这样来写统计性SQL:
select departid,
sum(salary) as total_sal,
sum(bonus) as total_bonus
from (select e.emid,e.ename,e.salary,e.departid,
e.salary* case when eb.types = 1 then .1
when eb.types = 2 then .2
else .3 end as bonus
from employee e,ebonus eb
where e.emid = eb.emid and e.departid =3 ) s group by departid
这条SQL查询结果如图一所示。这个结果部分不正确,及奖励总额对,而工资总额不对。原因是子查询中abc员工的工资多算了一次。我们单独执行from子查询的结果如下第二张图所示,即李可有两次奖励记录,所以统计汇总时多计算一次。如何改正?只要如下改正我们开始的写的SQL即可:
select departid,
sum(DISTINCT salary) as total_sal,
sum(bonus) as total_bonus
from (select e.emid,e.ename,e.salary,e.departid,
e.salary* case when eb.types = 1 then .1
when eb.types = 2 then .2
else .3 end as bonus
from employee e left outer join ebonus eb on ( e.emid = eb.emid)
where e.departid =3 ) s group by departid
这样就到处了正确的结果,如图三所示。
好了,这里重点要注意的是外连接以及聚合函数中的distinct的应用。自己试试吧。^_^


这一篇就先辑录到此了,点个赞分享出去吧,欢迎收藏备查 ^_^


相关推荐

RHEL8和CentOS8怎么重启网络

本文主要讲解如何重启RHEL8或者CentOS8网络以及如何解决RHEL8和CentOS8系统的网络管理服务报错,当我们安装好RHEL8或者CentOS8,重启启动网络时,会出现以下报错:...

Linux 内、外网双网卡路由配置

1.路由信息的影响Linux系统中如果有多张网卡的情况下,如果路由信息配置不正确,...

Linux——centos7修改网卡名

修改网卡名这个操作可能平时用不太上,可作为了解。修改网卡默认名从ens33改成eth01.首先修改网卡配置文件名(建议将原配置文件进行备份)...

CentOS7下修改网卡名称为ethX的操作方法

?Linux操作系统的网卡设备的传统命名方式是eth0、eth1、eth2等,而CentOS7提供了不同的命名规则,默认是基于固件、拓扑、位置信息来分配。这样做的优点是命名全自动的、可预知的...

Linux 网卡名称enss33修改为eth0

一、CentOS修改/etc/sysconfig/grub文件(修改前先备份)为GRUB_CMDLINE_LINUX变量增加2个参数(net.ifnames=0biosdevname=0),修改完成...

CentOS下双网卡绑定,实现带宽飞速

方式一1.新建/etc/sysconfig/network-scripts/ifcfg-bond0文件DEVICE=bond0IPADDR=191.3.60.1NETMASK=255.255.2...

linux 双网卡双网段设置路由转发

背景网络情况linux双网卡:网卡A(ens3)和网卡B(...

Linux-VMware设置网卡保持激活

Linux系统只有在激活网卡的状态下才能去连接网络,进行网络通讯。修改配置文件(永久激活网卡)...

VMware虚拟机三种网络模式

01.VMware虚拟机三种网络模式由于linux目前很热门,越来越多的人在学习linux,但是买一台服务放家里来学习,实在是很浪费。那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有v...

Rocky Linux 9/CentOS Stream 9修改网卡配置/自动修改主机名(实操)

推荐...

2023年最新版 linux克隆虚拟机 解决网卡uuid重复问题

问题描述1、克隆了虚拟机,两台虚拟机里面的ip以及网卡的uuid都是一样的2、ip好改,但是uuid如何改呢?解决问题1、每台主机应该保证网卡的UUID是唯一的,避免后面网络通信有问题...

Linux网卡的Vlan配置,你可能不了解的玩法

如果服务器上连的交换机端口已经预先设置了TRUNK,并允许特定的VLAN可以通过,那么服务器的网卡在配置时就必须指定所属的VLAN,否则就不通了,这种情形在虚拟化部署时较常见。例如在一个办公环境中,办...

Centos7 网卡绑定

1、切换到指定目录#备份网卡数据cd/etc/sysconfig/network-scriptscpifcfg-enp5s0f0ifcfg-enp5s0f0.bak...

Linux搭建nginx+keepalived 高可用(主备+双主模式)

一:keepalived简介反向代理及负载均衡参考:...

Linux下Route 路由指令使用详解

linuxroute命令用于显示和操作IP路由表。要实现两个不同子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现。在Linux系统中,设置路由通常是为了解决以下问题:该...

取消回复欢迎 发表评论: