纸飞机

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  22 随笔 :: 28 文章 :: 30 评论 :: 0 Trackbacks

问题:求特定列中的值占总和的百分比。例如,确定所有DEPTNO 10工资占总工资的百分比(DEPTNO 10的工资在总工资中的百分比数)。

解决方案

总的来说,在SQL中计算占总数的百分比跟书面计算一样:先除后乘。这个例子要计算表EMP中DEPTNO 10工资所占的百分比。首先,算出DEPTNO 10的工资,然后除以表中的工资总和,最后一步,乘以100,则返回一个表示百分比的值。

MySQL和PostgreSQL

DEPTNO 10的工资总和除以所有工资总和:

1 select (sum(

2           case when deptno = 10 then sal end)/sum(sal)

3          )*100 as pct

4    from emp

DB2、Oracle和SQL Server

使用内联视图及窗口函数SUM OVER,计算出所有工资总和以及DEPTNO 10的工资和。然后,在外层查询中进行除法和乘法操作:

1   select distinct (d10/total)*100 as pct

2     from (

3   select deptno,

4          sum(sal)over() total,

5          sum(sal)over(partition by deptno) d10

6     from emp

7          ) x

8    where deptno=10

讨论

MySQL和PostgreSQL

用CASE语句能够轻松地得到DEPTNO 10的工资。然后将它们加起来,并除以所有工资总和。由于聚集时会忽略NULL值,所以CASE语句中不必加入ELSE子句。如果想看到确切的被除数和除数,则可以执行不做除法的查询:

select sum(case when deptno = 10 then sal end) as d10,

        sum(sal)

   from emp

D10   SUM(SAL)

---- ---------

8750               29025

依定义SAL的方式不同,在进行除法操作时可能需要做显式类型转换。例如,在DB2、SQL Server和PostgreSQL中,如果SAL定义为整数,则可以把它转换为小数,以便得到正确答案,如下所示:

select (cast(

          sum(case when deptno = 10 then sal end)

              as decimal)/sum(sal)

         )*100 as pct

   from emp

DB2、Oracle和SQL Server

除传统解决方案外,该方案使用窗口函数计算相对于总数的百分数。对于DB2和SQL Server,如果SAL定义为整数类型,则在除法操作之前,需要进行类型转换:

select distinct

        cast(d10 as decimal)/total*100 as pct

   from (

select deptno,

        sum(sal)over() total,

        sum(sal)over(partition by deptno) d10

   from emp

        ) x

where deptno=10

必须记住,窗口函数在WHERE子句后执行。因此不能把针对DEPTNO的筛选放在内联视图X中。分别考虑一下内联视图X中包含及不包含DEPTNO筛选的结果。首先,看一下不包含DEPTNO筛选的结果:

select deptno,

        sum(sal)over() total,

        sum(sal)over(partition by deptno) d10

   from emp

DEP

------- --------- ---------

      10      29025       8750

      10      29025       8750

      10      29025       8750

      20      29025      10875

      20      29025      10875

      20      29025      10875

      20      29025      10875

      20      29025      10875

      30      29025       9400

      30      29025       9400

      30      29025       9400

      30      29025       9400

      30      29025       9400

      30      29025       9400

包含DEPTNO筛选的结果:

select deptno,

        sum(sal)over() total,

        sum(sal)over(partition by deptno) d10

   from emp

where deptno=10

DEPTNO      TOTAL        D10

------ --------- ---------

     10       8750       8750

     10       8750       8750

     10       8750       8750

由于窗口函数在WHERE子句后执行,因此TOTAL的值仅表示DEPTNO 10的工资之和,而实际上需要用TOTAL表示所有工资的总和。这就是必须把针对DEPTNO的筛选放在内联视图X外面的原因。

posted on 2008-05-14 21:46 纸飞机 阅读(9727) 评论(0)  编辑  收藏 所属分类: Database

只有注册用户登录后才能发表评论。


网站导航: