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

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

sinye56 2024-09-22 08:24 7 浏览 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的应用。自己试试吧。^_^


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


相关推荐

程序员:JDK的安装与配置(完整版)_jdk的安装方法

对于Java程序员来说,jdk是必不陌生的一个词。但怎么安装配置jdk,对新手来说确实头疼的一件事情。我这里以jdk10为例,详细的说明讲解了jdk的安装和配置,如果有不明白的小伙伴可以评论区留言哦下...

Linux中安装jdk并配置环境变量_linux jdk安装教程及环境变量配置

一、通过连接工具登录到Linux(我这里使用的Centos7.6版本)服务器连接工具有很多我就不一一介绍了今天使用比较常用的XShell工具登录成功如下:二、上传jdk安装包到Linux服务器jdk...

麒麟系统安装JAVA JDK教程_麒麟系统配置jdk

检查检查系统是否自带java在麒麟系统桌面空白处,右键“在终端打开”,打开shell对话框输入:java–version查看是否自带java及版本如图所示,系统自带OpenJDK,要先卸载自带JDK...

学习笔记-Linux JDK - 安装&配置

前提条件#检查是否存在JDKrpm-qa|grepjava#删除现存JDKyum-yremovejava*安装OracleJDK不分系统#进入安装文件目...

Linux新手入门系列:Linux下jdk安装配置

本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...

测试员必备:Linux下安装JDK 1.8你必须知道的那些事

1.简介在Oracle收购Sun后,Java的一系列产品就被整合到Oracle官网中,打开官网乍眼一看也不知道去哪里下载,还得一个一个的摸索尝试,而且网上大多数都是一些Oracle收购Sun前,或者就...

Linux 下安装JDK17_linux 安装jdk1.8 yum

一、安装环境操作系统:JDK版本:17二、安装步骤第一步:下载安装包下载Linux环境下的jdk1.8,请去官网(https://www.oracle.com/java/technologies/do...

在Ubuntu系统中安装JDK 17并配置环境变量教程

在Ubuntu系统上安装JDK17并配置环境变量是Java开发环境搭建的重要步骤。JDK17是Oracle提供的长期支持版本,广泛用于开发Java应用程序。以下是详细的步骤,帮助你在Ubuntu系...

如何在 Linux 上安装 Java_linux安装java的步骤

在桌面上拥抱Java应用程序,然后在所有桌面上运行它们。--SethKenlon(作者)无论你运行的是哪种操作系统,通常都有几种安装应用程序的方法。有时你可能会在应用程序商店中找到一个应用程序...

Windows和Linux环境下的JDK安装教程

JavaDevelopmentKit(简称JDK),是Java开发的核心工具包,提供了Java应用程序的编译、运行和开发所需的各类工具和类库。它包括了JRE(JavaRuntimeEnviro...

linux安装jdk_linux安装jdk软连接

JDK是啥就不用多介绍了哈,外行的人也不会进来看我的博文。依然记得读大学那会,第一次实验课就是在机房安装jdk,编写HelloWorld程序。时光飞逝啊,一下过了十多年了,挣了不少钱,买了跑车,娶了富...

linux安装jdk,全局配置,不同用户不同jdk

jdk1.8安装包链接:https://pan.baidu.com/s/14qBrh6ZpLK04QS8ogCepwg提取码:09zs上传文件解压tar-zxvfjdk-8u152-linux-...

运维大神教你在linux下安装jdk8_linux安装jdk1.7

1.到官网下载适合自己机器的版本。楼主下载的是jdk-8u66-linux-i586.tar.gzhttp://www.oracle.com/technetwork/java/javase/downl...

window和linux安装JDK1.8_linux 安装jdk1.8.tar

Windows安装JDK1.8的步骤:步骤1:下载JDK打开浏览器,找到JDK下载页面https://d.injdk.cn/download/oraclejdk/8在页面中找到并点击“下载...

最全的linux下安装JavaJDK的教程(图文详解)不会安装你来打我?

默认已经有了linux服务器,且有root账号首先检查一下是否已经安装过java的jdk任意位置输入命令:whichjava像我这个已经安装过了,就会提示在哪个位置,你的肯定是找不到。一般我们在...

取消回复欢迎 发表评论: