`
西门吹牛
  • 浏览: 227245 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

分析及开窗函数

阅读更多
转自http://hi.baidu.com/edgar108/blog/item/e24c7fd66b0817d7a144dfc8.html

我以oracle中的emp 和dept表为例,讲一下开窗函数。

假如,现在有这样的要求:查出所有的员工的名字ename,薪水sal 以及他的薪水占说有员工薪水的比例。
一开始,我们的思路可能是这样:
select ename ,sal ,sal/sum(sal) from emp;
但是这样写是不对的,sum()是一个单行统计函数,只返回一个值,不能和其他字段同时出现。
解决办法就是使用开窗函数over()
select ename ,sal ,sal/sum(sal) over() as percent from emp;
查询结果:
ENAME             SAL    PERCENT
---------- ---------- ----------
SMITH             800 .027562446
ALLEN            1600 .055124892
WARD             1250 .043066322
JONES            2975 .102497847
MARTIN           1250 .043066322
BLAKE            2850 .098191214
CLARK            2450 .084409991
SCOTT            3000 .103359173
KING             5000 .172265289
TURNER           1500 .051679587
ADAMS            1100 .037898363

ENAME             SAL    PERCENT
---------- ---------- ----------
JAMES             950 .032730405
FORD             3000 .103359173
MILLER           1300 .044788975

已选择14行。

上面的over是指把前面的函数(本例中是sum())当成开窗函数而不是统计函数,SQL标准允许讲所有的统计函数
用作开窗函数,使用over关键字来区分这两种用法。

上面的“sum(sal) over()”的意思是,对于每一条记录,都去计算一次sal的和。如果over关键字后的括号中的选项为空,

把上面的sql改进一下:
select ename ,sal ,'0'||round(sal/sum(sal) over(),3) as percent from emp;
查询结果:

ENAME             SAL PERCENT
---------- ---------- -----------------------------------------
SMITH             800 0.028
ALLEN            1600 0.055
WARD             1250 0.043
JONES            2975 0.102
MARTIN           1250 0.043
BLAKE            2850 0.098
CLARK            2450 0.084
SCOTT            3000 0.103
KING             5000 0.172
TURNER           1500 0.052
ADAMS            1100 0.038

ENAME             SAL PERCENT
---------- ---------- -----------------------------------------
JAMES             950 0.033
FORD             3000 0.103
MILLER           1300 0.045

已选择14行。

如果现在像查询每个员工的姓名ename,工资sal,以及他的工资占他所在部门的比例,按照上面的思路,这次要这样写:

select ename,deptno,sal,'0'|| round(sal/sum(sal) over(partition by deptno),3) from emp;

如果需要对sal排序,再partition by deptno 后面 再加上order by sal:

select ename,deptno,sal,'0'|| round(sal/sum(sal) over(partition by deptno order by sal),3) from emp;

ORDER BY 的完整语法为 ORDER BY 字段名 RANGE|ROWS BETWEEN 边界规则1 AND 边界规则2
RANGE 表示 按照值的范围进行范围的定义,而 ROWS 表示按照行的范围进行范围的定义

边界规则的取值见下表:

可取值                                                说明                                   示例

CURRENT ROW                              当前行

N PRECEDING                                 前N行                                    2 PRECEDING

UNBOUNDED PRECEDING          一直到第一条记录     

N FOLLOWING                                 后N行                                  2 FOLLOWING

UNBOUNDED FOLLOWING          一直到最后一条记录


但是,如果这样写,会报错:
select ename,deptno,sal,'0'|| round(sal/sum(sal) over(order by sal partition by deptno ),3) from emp;可能 order by不能写在partition by的前面。


如果现在按照员工的姓名排序,并计算工资的累加和:

select ename ,sal ,sum(sal) over(order by sal rows between unbounded preceding and current row) as result from emp;

order by sal rows between unbounded preceding and current row 的意思是: 按照sal进行排序,然后计算从第一行(unbounded preceding)到当前行
(current row)的和,这样的结果就是按照工资进行排序的工作值的累加和。

因为ROWS 表示按照行的范围进行范围的定义,所以计算从第一行到当前行的累加和。

如果把ROWS换成 RANGE :

select ename ,sal ,sum(sal) over(order by sal range between unbounded preceding and current row) as result from emp;

ENAME             SAL     RESULT
---------- ---------- ----------
SMITH             800        800
JAMES             950       1750 (800+950)
ADAMS            1100       2850 (800+950+1100)
WARD             1250       5350
MARTIN           1250       5350
MILLER           1300       6650
TURNER           1500       8150
ALLEN            1600       9750
CLARK            2450      12200
BLAKE            2850      15050
JONES            2975      18025

ENAME             SAL     RESULT
---------- ---------- ----------
SCOTT            3000      24025
FORD             3000      24025
KING             5000      29025

已选择14行。


RANGE 表示 按照值的范围进行范围的定义 ,在计算累加和的过程中,如果遇到相同的值(本例中为sal),则计算所有的相同值同时累加
(本例中SCOTT,FORD的sal全是3000,所以值是 18025+3000+3000=24025)

select ename ,sal ,sum(sal) over(order by sal rows between 2 preceding and 2 following) as result from emp;

ENAME             SAL     RESULT
---------- ---------- ----------
SMITH             800       2850 (800+950+1100)
JAMES             950       4100
ADAMS            1100       5350
WARD             1250       5850
MARTIN           1250       6400
MILLER           1300       6900
TURNER           1500       8100 (1250+1300+1500+1600+2450)
ALLEN            1600       9700
CLARK            2450      11375
BLAKE            2850      12875
JONES            2975      14275 (2450+2850+2975+3000+3000)

ENAME             SAL     RESULT
---------- ---------- ----------
SCOTT            3000      16825
FORD             3000      13975
KING             5000      11000 (3000+3000+5000)

已选择14行。

sum(sal) over(order by sal rows between 2 preceding and 2 following)
按照sal进行排序,然后计算从当前行前两行(2 preceding) 到 当前行后两行(2 following)的累加和

对于第1行到第2行(n=2),“前2行”是不存在或不完整的,所以按照前两行不存在或不完整来计算,最后2行类似。

select ename ,sal ,sum(sal) over(order by sal rows between 1 following and 3 following) as result from emp;

ENAME             SAL     RESULT
---------- ---------- ----------
SMITH             800       3300 (950+1100+1250)
JAMES             950       3600
ADAMS            1100       3800
WARD             1250       4050
MARTIN           1250       4400
MILLER           1300       5550
TURNER           1500       6900
ALLEN            1600       8275
CLARK            2450       8825
BLAKE            2850       8975
JONES            2975      11000

ENAME             SAL     RESULT
---------- ---------- ----------
SCOTT            3000       8000
FORD             3000       5000
KING             5000                 (后面没有数据了,所以是NULL)

已选择14行。

计算的某一列后1行到后3行的值

select ename ,sal ,sum(sal) over(order by sal range between unbounded preceding and current row) as result from emp;

select ename ,sal ,sum(sal) over(order by sal) as result from emp;
是等价的。
也就是说 range between unbounded preceding and current row 是默认的定位方式。

select ename ,sal ,count(*) over(order by sal desc rows between unbounded preceding and current row) as result from emp;

ENAME             SAL     RESULT
---------- ---------- ----------
KING             5000          1
FORD             3000          2
SCOTT            3000          3
JONES            2975          4
BLAKE            2850          5
CLARK            2450          6
ALLEN            1600          7
TURNER           1500          8
MILLER           1300          9
WARD             1250         10
MARTIN           1250         11

ENAME             SAL     RESULT
---------- ---------- ----------
ADAMS            1100         12
JAMES             950         13
SMITH             800         14

已选择14行。
order by sal desc rows between unbounded preceding and current row 表示按照sal的降序排列,计算从第一行到当前行的个数,所以这个可以看作员工工资的排名。
分享到:
评论

相关推荐

    oracle分析函数及开窗函数

    ### Oracle分析函数及开窗函数详解 #### 一、Oracle分析函数概述 Oracle自8.1.6版本开始引入了分析函数,这类函数主要用于计算基于组的聚合值,并且与传统的聚合函数不同的是,分析函数可以针对每个组返回多行结果...

    oracle开窗函数学习技巧总结

    在Oracle数据库中,开窗函数是一种非常强大的功能,它能够帮助我们对数据进行更复杂的分析和处理。开窗函数允许我们在查询结果集的一个窗口内执行聚合操作,而无需对数据进行物理排序或分组。本文将重点介绍`OVER`...

    oracle分析函数over_及开窗函数.txt

    ### Oracle分析函数OVER及开窗函数详解 #### 一、概述 在Oracle数据库中,分析函数(Analytic Functions)是一种非常强大的工具,用于处理复杂的查询需求。这些函数可以在一组相关的行上执行计算,并且每行返回一个...

    oracle的分析函数over 及开窗函数

    ### Oracle的分析函数OVER及开窗函数 #### 一、分析函数OVER ##### 1. 概念介绍 从Oracle 8.1.6版本开始,Oracle引入了分析函数,这些函数可以对分组的数据执行复杂的操作,如计算累积总和、排名等。与聚合函数...

    SQL开窗函数详解.pdf

    开窗函数,又称分析函数或OLAP函数,是SQL中一种高级特性,它允许用户在保持与原始数据行关联的同时执行复杂的计算和聚合操作。这些功能极大地提高了SQL查询的灵活性和分析能力,让用户能够更加深入地洞察数据的内在...

    Oracle 语法之 OVER (PARTITION BY ..) 及开窗函数(转载)

    ### Oracle 语法之 OVER (PARTITION BY ..) 及开窗函数详解 #### 一、OVER (PARTITION BY ..) 概述 在Oracle数据库中,`OVER (PARTITION BY ...)` 是一种非常强大的功能,它允许用户在数据集上进行窗口操作。这在...

    Hive开窗函数测试-cube,rollup

    为了更好地理解这些概念,你可以参考提供的文档“Hive开窗函数测试.docx”。这个文档应该包含了具体的示例和代码,展示了如何在Hive SQL查询中使用窗口函数、cube和rollup。通过实践这些示例,你可以更深入地了解...

    SQL开窗函数介绍以及示例

    SQL开窗函数(Window Functions)是一种用于在查询结果集中执行聚合、排序和分析操作的强大工具。它们可以在不破坏查询结果集的情况下,对每一行数据进行计算,比如计算行的排名、累计和、移动平均等。以下是SQL开窗...

    SQL中的开窗函数详解可代替聚合函数使用

    总之,开窗函数是SQL查询中的一个重要概念,它极大地增强了SQL的表达能力,使得在处理复杂的数据分析任务时更加得心应手。理解并熟练掌握开窗函数,对于提升SQL编程技能和提高数据处理效率具有重要意义。

    hive开窗函数详细介绍

    本文将详细探讨Hive的开窗函数,包括ROW_NUMBER、RANK、DENSE_RANK以及分析窗口函数SUM、AVG、MIN和MAX的用法。 一、窗口函数 1. ROW_NUMBER() ROW_NUMBER()函数为每个分区内的记录分配一个唯一的连续编号,根据...

    开窗函数有浅入深详解(一)

    总的来说,开窗函数是SQL查询的一个重要扩展,它使开发者能够处理更复杂的数据分析任务,而无需编写复杂的子查询或存储过程。掌握开窗函数的使用,对于任何数据库开发人员来说都是必不可少的技能,能够提升处理大...

    SQL开窗函数的具体实现详解

    SQL开窗函数是一种在SQL查询中执行复杂分析的高级技术,它允许你在同一查询中对一组相关行(称为“窗口”或“分组”)进行聚合操作,而不仅仅是整个结果集。这使得处理复杂的排序、分组和计算变得更加便捷。在2003年...

    Oracle数据库中SQL开窗函数的使用

    这是因为开窗函数的计算基于一个动态定义的“窗口”,这个窗口可以根据需要在数据集上滑动,允许对每一行的上下文进行更细致的分析。 在Oracle数据库中,开窗函数通常被称为分析函数。以Oracle为例,我们可以利用...

    hive开窗函数.docx

    Hive 开窗函数是数据分析和处理中的重要工具,它们允许用户在特定的数据集窗口内执行复杂的计算和分析,而不仅仅是对整个数据集进行全局操作。这些函数极大地增强了 Hive 查询的能力,使得用户能够处理更复杂的业务...

    sql开窗函数详解.rar

    SQL开窗函数是数据库查询中的一个...SQL开窗函数极大地扩展了我们处理和分析数据的能力,无论是在报表制作、数据分析还是业务智能场景中,都能发挥重要作用。掌握这些函数的用法,将有助于提升SQL查询的灵活性和效率。

    SQL开窗函数.zipSQL开窗函数.zipSQL开窗函数.zip

    SQL开窗函数是数据库查询中的一个强大工具,它允许在单个SQL语句中进行复杂的分析操作,如计算累计和、排名、移动平均等。在SQL中,窗口(或称为分区)是根据某些条件对数据集进行分组的一段连续记录。通过使用窗口...

Global site tag (gtag.js) - Google Analytics