3.9 聚集和联接

问题:要在包含多个表的查询中执行聚集运算,要确保表间连接不能使聚集运算发生错误.例如,要查找在部门10中所有员工的工资合计和奖金合计.由于有些员工的奖金激励不只一条,在表emp和表emp_bonus之间做连接会导致聚集函数sum算得的值错误.

现在,考虑一下下面的返回的在部门10中所有员工的工资和奖金的查询。表bonus中的type字段决定奖金额,类型1的奖金为员工工资的10%,类型2为20%,类型3为30%。

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


进行到这,一切正常,然而为了计算奖金总数而跟表emp_bonus做联接时,错误出现了:

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


尽管total_bonus所返回的值是正确的,total_sal却是错误的。

total _sal为什么错了,因为联接导致sal列存在重复。考虑下面的查询。该查询联接表emp和emp_bonus

select e.ename,e.sal
    from emp e,emp_bonus eb
        where e.empno = eb.empno
            and e.deptno =10


现在可以很容易的看出total_sal为什么错了,因为miller的工资被统计了两次。

解决方案:当处理聚集与联接混合操作时,一定要小心。如果联接产生重复行,可以有两种方法来避免聚集函数计算错误,方法之一,只要在调用聚集函数时使用关键字distinct,这样每个值只参与计算一次,另一种方法是,在进行连接前先只想聚集操作(在内联视图中),这样,因为聚集计算已经在连接前完成了,所以就可以避免聚集函数计算错误,从而可以完全避免产生此问题。下面列出的解决方案使用了distinct关键字,而”讨论”部分将讨论如何在联结前使用内联视图来只想聚集操作。


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

原文地址:https://www.cnblogs.com/l10n/p/7518475.html