摘要:组合使用连接查询与聚合函数例如,希望计算部门编号为的员工工资总额以及奖金总和。因为有部分员工多次获得奖金,所以在表和表连接之后再执行聚合函数,会得出错误的计算结果。
叠加两个行集
显示EMP表里部门编号为10的员工姓名和部门编号,以及DEPT表中各个部门的名称和编号。
select ename as ename_and_dname, deptno from emp where deptno = 10 union all select "--------", null from t1 union all select dname, deptno from dept;查找两个表中相同的行
考虑如下视图V:
从EMP表中获取与视图V相匹配的全部员工的EMPNO, ENAME, JOB, SAL, DEPTNO。
select e.empno, e.ename, e.job, e.sal, e.deptno from emp e, V where e.ename = v.ename and e.job = v.job and e.sal = v.sal;
join子句
select e.empno, e.ename, e.job, e.sal, e.deptno from emp e join V on ( e.ename = v.ename and e.job = v.job and e.sal = v.sal );
使用集合运算INTERSECT和谓词IN
集合运算INTERSECT会返回两个行集的相同部分,在使用INTERSECT时,必须保证两个表里参与的项目数目是相同的,并且数据类型也是相同的。注意,当执行集合运算时,默认不会返回重复项。
select empno, ename, job, sal, deptno from emp where (ename, job, sal) in ( select ename, job, sal from emp intersect select ename, job, sal from V )查找只存在于一个表中的数据
Oracle
select deptno from dept minus select deptno from emp;
MySQL(应注意IN与NOT IN的区别,看下节)
select deptno from dept where deptno not in (select deptno from emp);IN与NOT IN
IN与NOT IN本质上是OR运算,由于NULL值参与OR逻辑运算的方式不同,IN和NOT IN将会产生不同的结果。如:
select deptno from dept where deptno in (10, 50, null);
select deptno from dept where (deptno = 10 or deptno = 50 or deptno = null);
结果均为:
但是NOT IN:
select deptno from dept where deptno not in (10, 50, null);
select deptno from dept where not (deptno = 10 or deptno = 50 or deptno = null);
因为
not (deptno = 10 or deptno = 50 or deptno = null)
等价于
deptno <> 10 and deptno <> 50 and deptno <> null
而对于null来说,它应该理解为未知(UNKNOWN),在任何等式中,等价于UNKNOWN的判断均不会返回任何值。
参考Oracle官方对NULL值的解释
为了避NOT IN和NULL值带来的问题,可以结合NOT EXISTS和关联子查询。
select d.deptno from dept d where not exists ( select null from emp e where d.deptno = e.deptno )从一个表检索与另一个表不相关的行
例如:找出哪些部门没有员工
MySQL及Oracle 9i和后续版本
select d.* from dept d left outer join emp e on (d.deptno = e.deptno) where e.deptno is null;
Oracle 8i及更早版本
select d.* from dept d, emp e where d.deptno = e.deptno(+) and e.deptno is null;
保留不匹配的行,这种操作可以成为反连接,为了更好理解,可以看一下过滤null值之前的结果集:
select e.ename, e.deptno as emp_deptno, d.* from dept d left outer join emp e on (d.deptno = e.deptno);
所以解决方案就是使用where子句,只保留EMP_DEPTNO是NULL值的结果集。
确定两个表是否有相同的数据考虑如下视图:
create view V as select * from emp where deptno != 10 union all select * from emp where ename = "WARD";
要找出该视图与EMP表的不同数据和重复数据:
也就是说,我们要找出存在于EMP表而不在视图V中的DEPTNO为10的三条数据,以及在EMP表中ENAME为WARD的一条数据和在视图V中ENAME为WARD的两条重复数据。
Oracle
( select empno, ename, job, mgr, hiredate, sal, comm, deptno, count(*) as cnt from V group by empno, ename, job, mgr, hiredate, sal, comm, deptno minus select empno, ename, job, mgr, hiredate, sal, comm, deptno, count(*) as cnt from emp group by empno, ename, job, mgr, hiredate, sal, comm, deptno ) union all ( select empno, ename, job, mgr, hiredate, sal, comm, deptno, count(*) as cnt from emp group by empno, ename, job, mgr, hiredate, sal, comm, deptno minus select empno, ename, job, mgr, hiredate, sal, comm, deptno, count(*) as cnt from V group by empno, ename, job, mgr, hiredate, sal, comm, deptno );
MySQL
( select * from ( select e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal, e.comm, e.deptno, count(*) as cnt from emp e group by empno, ename, job, mgr, hiredate, sal, comm, deptno ) e where not exists ( select null from ( select v.empno, v.ename, v.job, v.mgr, v.hiredate, v.sal, v.comm, v.deptno, count(*) as cnt from V group by empno, ename, job, mgr, hiredate, sal, comm, deptno ) v where v.empno = e.empno and v.ename = e.ename and v.job = e.job and v.mgr = e.mgr and v.hiredate = e.hiredate and v.sal = e.sal and v.deptno = e.deptno and v.cnt = e.cnt and coalesce(v.comm, 0) = coalesce(e.comm, 0) ) ) union all ( select * from ( select v.empno, v.ename, v.job, v.mgr, v.hiredate, v.sal, v.comm, v.deptno, count(*) as cnt from V group by empno, ename, job, mgr, hiredate, sal, comm, deptno ) v where not exists ( select null from ( select e.empno, e.ename, e.job, e.mgr, e.hiredate, e.sal, e.comm, e.deptno, count(*) as cnt from emp e group by empno, ename, job, mgr, hiredate, sal, comm, deptno ) e where v.empno = e.empno and v.ename = e.ename and v.job = e.job and v.mgr = e.mgr and v.hiredate = e.hiredate and v.sal = e.sal and v.deptno = e.deptno and v.cnt = e.cnt and coalesce(v.comm, 0) = coalesce(e.comm, 0) ) )
之所以使用group by是为了找到在每个表或者视图中找到重复数据并统计CNT,以作为结果集的字段出现。
组合使用连接查询与聚合函数例如,希望计算部门编号为10的员工工资总额以及奖金总和。因为有部分员工多次获得奖金,所以在EMP表和EMP_BONUS表连接之后再执行聚合函数SUM,会得出错误的计算结果。EMP_BONUS表数据如下:
显然EMP_BONUS表中EMPNO数据有重复。先查看10部门的工资和奖金:
select e.empno, e.ename, e.sal, e.deptno, e.sal * case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end as bonus from emp e, emp_bonus eb where e.empno = eb.empno and e.deptno = 10;
所以按照如下方式进行工资和奖金的总和计算,将导致工资总额发生错误:
select deptno, sum(sal) as total_sal, sum(bonus) as total_bonus from ( select e.empno, e.ename, e.sal, e.deptno, e.sal * case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end as bonus from emp e, emp_bonus eb where e.empno = eb.empno and e.deptno = 10 ) x group by deptno;
可以使用distinct关键字:
MySQL & Oracle
select deptno, sum(distinct sal) as total_sal, sum(bonus) as total_bonus from ( select e.empno, e.ename, e.sal, e.deptno, e.sal * case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end as bonus from emp e, emp_bonus eb where e.empno = eb.empno and e.deptno = 10 ) x group by deptno;
Oracle也可以使用窗口函数SUM OVER
Oracle
select distinct deptno, total_sal, total_bonus from ( select e.empno, e.ename, sum(distinct e.sal) over (partition by e.deptno) as total_sal, e.deptno, sum(e.sal * case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end) over (partition by deptno) as total_bonus from emp e, emp_bonus eb where e.empno = eb.empno and e.deptno = 10 ) x;
关于窗口函数,可以查看本书附录
《SQL经典实例》第三章
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/32315.html
摘要:前言在之前已经大概了解过数据库和学过相关的知识点,但是太久没用过了,就基本忘了印象中就只有基本的语句和相关一些概念写下本博文的原因就是记载着一些以前没注意到的知识点以后或许会有用实例与数据库概念数据库服务器由两部分组成实例理解为对象看不见的 前言 在之前已经大概了解过Mysql数据库和学过相关的Oracle知识点,但是太久没用过Oracle了,就基本忘了...印象中就只有基本的SQL语...
摘要:个人博客地址方案项目背景在现在题库架构下,针对新购买的多道数据进行整合,不影响现有功能。数据切分尽量通过数据冗余或表分组来降低跨库的可能。 个人博客地址 https://www.texixi.com/2019/0... 方案 项目背景 在现在题库架构下,针对新购买的1300W多道数据进行整合,不影响现有功能。由于数据量偏多,需要进行数据的切分 目标场景 兼容旧的功能 对1300多W...
摘要:个人博客地址方案项目背景在现在题库架构下,针对新购买的多道数据进行整合,不影响现有功能。数据切分尽量通过数据冗余或表分组来降低跨库的可能。 个人博客地址 https://www.texixi.com/2019/0... 方案 项目背景 在现在题库架构下,针对新购买的1300W多道数据进行整合,不影响现有功能。由于数据量偏多,需要进行数据的切分 目标场景 兼容旧的功能 对1300多W...
摘要:一是常用的策略,通过外键来表示继承,父类和子类分别位于不同的表中,子类表包含自身属性列和父类表的外键,并将父表的外键作为子类表的主键。与父类的多态关联将被表示为引用父类表的外键。 继承是面向对象开发时经常用到的,但是SQL Server 数据库不具备继承,那么怎么办能?我们可以利用如下三种方法: TPH(Table per Hierachy):对SQL架构进行非规范化来表示多态,使用...
摘要:一是常用的策略,通过外键来表示继承,父类和子类分别位于不同的表中,子类表包含自身属性列和父类表的外键,并将父表的外键作为子类表的主键。与父类的多态关联将被表示为引用父类表的外键。 继承是面向对象开发时经常用到的,但是SQL Server 数据库不具备继承,那么怎么办能?我们可以利用如下三种方法: TPH(Table per Hierachy):对SQL架构进行非规范化来表示多态,使用...
阅读 3288·2023-04-25 19:56
阅读 1431·2021-11-12 10:36
阅读 1546·2021-11-08 13:19
阅读 1367·2019-08-30 14:06
阅读 2846·2019-08-30 11:01
阅读 1574·2019-08-29 13:23
阅读 2572·2019-08-29 11:18
阅读 3296·2019-08-26 13:35