分析函数用于计算一组行的聚合值,由分析函数语法定义的行集叫做窗口,窗口的大小由物理行数或逻辑间隔决定。每一行上的滑动窗口都是已定义的,窗口决定了对某一行而言进行计算的行的范围。从查询结果和查询语法来看,分析函数与聚合函数主要有 3 点不同:

  • 1、聚合函数每组只返回一条记录,而分析函数每组可返回多条记录。
  • 2、在单个查询中,多个聚合函数只能作用于同一个分组,而不同分析函数可作用于不同分组。
  • 3、在分组查询中,查询列表只能出现聚合函数或 GROUP BY 子句中出现过的字段或常量或表达式,而分析函数没有这些限制。

1、函数语法

我理解的分析函数无非也就是由一或多个普通的函数或子句按照一定的规则构成的复杂数据分析函数。换言之,分析函数内部有些函数或子句的语法规则之前已经讲述过了,这里将不再赘述,本节将着重讲述分析函数所特有的一些函数或子句的语法。

1.1、语法概述

有很多网站都把分析函数称之为窗口函数,又称 OVER 为开窗函数,还有些似是而非的概念我本人也不甚了解。我特地查阅过 《Oracle Database SQL Reference 10g Release 2》Analytic Functions,语法如下:

  1. analytic_function([arguments]) OVER([analytic_clause])

参数说明:

  • analytic_function:分析函数的名称。Oracle 10g R2 中内置了 30 个分析函数。
  • arguments:分析函数的参数。内置的分析函数一般带 0~3 个参数,参数可以是任何数字类型或是可以隐式转换为数字类型的数据类型。
  • OVER:用来标识函数是个分析函数。对于即可作为聚合函数又可作为分析函数的函数,Oracle 无法识别,必须用 OVER 来标识此函数为分析函数。但并不是说只可作为分析函数的函数就无需标识,是分析函数就必须用 OVER 关键字来标识。另外 OVER 后面的一对小括号也是必须的,即便括号中什么都不包含。
  • analytic_clause:用来确定分析规则。语法是:[query_partition_clause][order_by_clause[windowing_clause]],语法中的 3 个子句都是可选的,但 windowing_clause 必须依赖于 order_by_clause 而存在。
    • query_partition_clause:分组子句,用于确定窗口,与 GROUP BY 语句的语法类似。
    • order_by_clause:排序子句,用于确定窗口规则,与 ORDER BY 语句的语法类似。
    • windowing_clause:窗口范围子句,用于确定分组中当前的计算范围。

1.2、窗口详解

《Oracle Database SQL Reference 10g Release 2》 中给出 windowing_clause 语法示意图如下:

  • ROWS:用于指定窗口由物理行构成,即符合指定的数据行的范围。
  • RANGE:用于指定窗口由逻辑偏移量构成,即符合指定的逻辑条件的范围。
  • BETWEEN...AND:用于指定窗口的起始点和终结点。
  • UNBOUNDED PRECEDING:用于指明窗口开始于分组的第一行。
  • CURRENT ROW:作为起始点,指明窗口开始于当前行或当前行的值;作为终结点,指明窗口结束于当前行或当前行的值。
  • UNBOUNDED FOLLOWING:用于指明窗口结束于分组的最后一行。
  • value_expr:物理或逻辑偏移量的表达式。

无论是窗口大小是由物理行数(ROWS)确定,还是由逻辑间隔(RANGE)确定,在分组中窗口总是从上往下滑动。窗口范围可以由 BETWEEN...AND 限定,也可以不用 BETWEEN...AND,不用则表示窗口到当前行或值结束。

1.2.1、ROWS 窗口

ROWS 窗口是由分组排序后分组中若干连续的行所构成的窗口。在 ROWS 窗口中 value_expr 是物理偏移量,它必须是常量或值为非负数的表达式。合法的 ROWS 窗口范围定义共有 16 种,列举如下:

1、窗口开始于分组第一行,结束于分组最后一行。

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

2、窗口开始于分组第一行,结束于当前行。

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  2. ROWS UNBOUNDED PRECEDING

3、窗口开始于分组第一行,结束于当前行的前 value_expr 行。

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND value_expr PRECEDING

4、窗口开始于分组第一行,结束于当前行的后 value_expr 行。

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND value_expr FOLLOWING

5、窗口开始于当前行,结束于分组最后一行。

  1. ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING

6、窗口开始于当前行,结束于当前行。

  1. ROWS BETWEEN CURRENT ROW AND CURRENT ROW
  2. ROWS CURRENT ROW

7、窗口开始于当前行,结束于当前行的前 value_expr 行。

  1. ROWS BETWEEN CURRENT ROW AND value_expr PRECEDING

8、窗口开始于当前行,结束于当前行的后 value_expr 行。

  1. ROWS BETWEEN CURRENT ROW AND value_expr FOLLOWING

9、窗口开始于当前行的前 value_expr 行,结束于当前行。

  1. ROWS BETWEEN value_expr PRECEDING AND CURRENT ROW
  2. ROWS value_expr PRECEDING

10、窗口开始于当前行的前 value_expr1 行,结束于当前行的前 value_expr2 行。前提是要满足 value_expr1 >= value_expr2。

  1. ROWS BETWEEN value_expr1 PRECEDING AND value_expr2 PRECEDING

11、窗口开始于当前行的前 value_expr1 行,结束于当前行的后 value_expr2 行。

  1. ROWS BETWEEN value_expr1 PRECEDING AND value_expr2 FOLLOWING

12、窗口开始于当前行的后 value_expr 行,结束于分组最后一行。

  1. ROWS BETWEEN value_expr FOLLOWING AND UNBOUNDED FOLLOWING

13、窗口开始于当前行的后 value_expr1 行,结束于当前行的后 value_expr2 行。前提是要满足 value_expr1 <= value_expr2。

  1. ROWS BETWEEN value_expr1 FOLLOWING AND value_expr2 FOLLOWING
1.2.2、RANGE 窗口

RANGE 窗口是由分组排序后分组中满足指定逻辑条件的行所构成的窗口。在 RANGE 窗口中 value_expr 为逻辑偏移量,它必须是常量或值为非负数的表达式或间隔值。当 value_expr 值是一个数字时,排序字段必须是数字或日期类型;当 value_expr 值是一个间隔值时,排序字段必须是一个日期类型。合法的 RANGE 窗口范围定义也有 16 种,列举如下:

1、升序排序时,表达式介于第一行的值和最后一行的值之间;降序排序时,表达式介于最后一行的值和第一行的值之间。

  1. RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

2、升序排序时,表达式介于第一行的值和当前行的值之间;降序排序时,表达式介于当前行的值和第一行的值之间。若不指定窗口,则默认为该窗口

  1. RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  2. RANGE UNBOUNDED PRECEDING

3、升序排序时,表达式介于第一行的值和当前行的值 -value_expr 之间;降序排序时,表达式介于当前行的值 -value_expr 和第一行的值之间。

  1. RANGE BETWEEN UNBOUNDED PRECEDING AND value_expr PRECEDING

4、升序排序时,表达式介于第一行的值和当前行的值 +value_expr 之间;降序排序时,表达式介于当前行的值 +value_expr 和第一行的值之间。

  1. RANGE BETWEEN UNBOUNDED PRECEDING AND value_expr FOLLOWING

5、升序排序时,表达式介于当前行的值和最后一行的值之间;降序排序时,表达式介于最后一行的值和当前行的值之间。

  1. RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING

6、表达式等于当前行的值。

  1. RANGE BETWEEN CURRENT ROW AND CURRENT ROW
  2. RANGE CURRENT ROW

7、表达式介于当前行的值和当前行的值 +value_expr 之间。

  1. RANGE BETWEEN CURRENT ROW AND value_expr FOLLOWING

8、表达式介于当前行的值 -value_expr 和最后一行的值之间。

  1. RANGE BETWEEN value_expr PRECEDING AND UNBOUNDED FOLLOWING

9、表达式介于当前行的值 -value_expr 和当前行的值之间。

  1. RANGE BETWEEN value_expr PRECEDING AND CURRENT ROW
  2. RANGE value_expr PRECEDING

10、表达式介于当前行的值 -value_expr1 和当前行的值 -value_expr2 之间。前提是要满足 value_expr1 >= value_expr2。

  1. RANGE BETWEEN value_expr1 PRECEDING AND value_expr2 PRECEDING

11、表达式介于当前行的值 -value_expr1 和当前行的值 +value_expr2 之间。

  1. RANGE BETWEEN value_expr1 PRECEDING AND value_expr2 FOLLOWING

12、升序排序时,表达式介于当前行的值 +value_expr 和最后一行的值之间;降序排序时,表达式介于最后一行的值和当前行的值 +value_expr 之间。

  1. RANGE BETWEEN value_expr FOLLOWING AND UNBOUNDED FOLLOWING

13、表达式介于当前行的值 +value_expr1 和当前行的值 +value_expr2 之间。前提是要满足 value_expr1 <= value_expr2。

  1. RANGE BETWEEN value_expr1 FOLLOWING AND value_expr2 FOLLOWING

2、函数用法

Oracle 10g R2 中内置的分析函数有 38 个,本节按函数用途将其分为 4 类,分别是:普通统计函数、数据排序函数、数据分布函数及统计分析函数,并逐一给出函数释义和用法示例。

2.1、普通统计类函数

  • MAX:对组内的数据窗口中的字段或表达式求最大值。
  • MIN:对组内的数据窗口中的字段或表达式求最小值。
  • AVG:对组内的数据窗口中的字段或表达式求平均值。
  • SUM:对组内的数据窗口中的字段或表达式求合计值。
  • COUNT:对组内的数据窗口中的数据行进行累计计数。

示例 1:

  1. SELECT t.staff_name,t.dept_code,t.base_salary,t.post_salary,
  2. MAX(t.post_salary) OVER(PARTITION BY t.dept_code) max_salary, -- 部门最高岗位工资
  3. MIN(t.post_salary) OVER(PARTITION BY t.dept_code) min_salary, -- 部门最低岗位工资
  4. AVG(t.post_salary) OVER(PARTITION BY t.dept_code) avg_salary, -- 部门平均岗位工资
  5. SUM(t.post_salary) OVER(PARTITION BY t.dept_code) sum_salary, -- 部门岗位工资之和
  6. COUNT(t.post_salary) OVER(PARTITION BY t.dept_code) cnt_salary -- 部门工资份数
  7. FROM demo.t_staff t
  8. ORDER BY t.dept_code,t.post_salary;

示例 2:

  1. SELECT t.staff_name,t.dept_code,t.base_salary,t.post_salary,
  2. -- 部门内截至当前行的最高岗位工资
  3. MAX(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary ROWS UNBOUNDED PRECEDING) max_salary,
  4. -- 部门内当前行至最后一行的最低岗位工资
  5. MIN(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary ROWS CURRENT ROW) min_salary,
  6. -- 部门内第一行至前一行的平均岗位工资
  7. AVG(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) avg_salary,
  8. -- 部门内第一行至后一行的岗位工资之和
  9. SUM(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary ROWS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING) sum_salary,
  10. -- 部门内截至当前行的工资份数
  11. COUNT(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary ROWS UNBOUNDED PRECEDING) cnt_salary
  12. FROM demo.t_staff t
  13. ORDER BY t.dept_code,t.post_salary;

2.2、数据排序类函数

  • RANK():根据 ORDER BY 的排序结果,计算组间相对位置,可能跳号。组内数据按 ORDER BY 子句排序,每一行都会得到一个序号,从而形成一个序列,该序列从 1 开始,往后 ORDER BY 表达式的值每发生一次变化,该序列也随之加 1。值相同的行将得到相同的序号(NULL 被认为是相等的),后面行的序号将发生跳跃。如前两行的序号为 1,则没有序号 2,第 3 行将得到序号 3。
  • DENSE_RANK():根据 ORDER BY 的排序结果,计算组间相对位置,不会跳号。DENSE_RANK 与 RANK 类似,也会得到一个首项为 1、公差为 1 的等差序列,值相同的行序号也相同(也认为 NULL 是相等的),但序号不会跳跃。如前两行的序号为 1,第 3 行将得到序号 2。
  • FIRST_VALUE(expression):返回组内数据窗口的第一个值。
  • LAST_VALUE(expression):返回组内数据窗口的最后一个值。
  • LAG(expression [, offset [, default] ]):可以访问结果集中当前行之前的行而不用进行自连接,这样就可以从组中与当前行一起选取当前行之前的行。offset 是一个正整数,默认值为 1,若不指定 offset,或 offset 的值超出窗口范围,就启用默认值。
  • LEAD(expression [, offset [, default] ]):与 LAG 相反,LEAD 可以访问结果集中当前行之后的行而不用进行自连接,这样就可以从组中与当前行一起选取当前行之后的行。offset 是一个正整数,默认值为 1,若不指定 offset,或 offset 的值超出窗口范围,就启用默认值。
  • ROW_NUMBER:返回有序组中一行的偏移量,按特定的排序分配行号。
  • FIRST:从紧凑排序后的结果集中筛选出排在最前面的一个值的行(可能是多行,因为值可能相等)。
  • LAST:从紧凑排序后的结果集中筛选出排在最后面的一个值的行(可能是多行,因为值可能相等)。

示例 1:

  1. SELECT t.dept_code,t.staff_name,t.post_salary,
  2. RANK() OVER(ORDER BY t.dept_code,t.post_salary) rank,
  3. DENSE_RANK() OVER(ORDER BY t.dept_code,t.post_salary) dense_rank,
  4. FIRST_VALUE(t.post_salary) OVER(ORDER BY t.dept_code,t.post_salary) fist_value,
  5. LAST_VALUE(t.post_salary) OVER(ORDER BY t.dept_code,t.post_salary) last_value,
  6. LAG(t.post_salary,1,0) OVER(ORDER BY t.dept_code,t.post_salary) lag_value,
  7. LEAD(t.post_salary,1,0) OVER(ORDER BY t.dept_code,t.post_salary) lead_value,
  8. ROW_NUMBER() OVER(ORDER BY t.dept_code,t.post_salary) row_number
  9. FROM demo.t_staff t
  10. ORDER BY t.dept_code,t.post_salary;

示例 2:

  1. SELECT t.dept_code,t.staff_name,t.birthday,t.post_salary,
  2. RANK() OVER(PARTITION BY t.dept_code ORDER BY t.post_salary) rank,
  3. DENSE_RANK() OVER(PARTITION BY t.dept_code ORDER BY t.post_salary) dense_rank,
  4. FIRST_VALUE(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary) fist_value,
  5. LAST_VALUE(t.post_salary) OVER(PARTITION BY t.dept_code ORDER BY t.post_salary) last_value,
  6. LAG(t.post_salary,1,0) OVER(PARTITION BY t.dept_code ORDER BY t.dept_code,t.post_salary) lag_value,
  7. LEAD(t.post_salary,1,0) OVER(PARTITION BY t.dept_code ORDER BY t.dept_code,t.post_salary) lead_value,
  8. ROW_NUMBER() OVER(PARTITION BY t.dept_code ORDER BY t.dept_code,t.post_salary) row_number
  9. FROM demo.t_staff t
  10. ORDER BY t.dept_code,t.post_salary;

示例 3:

  1. SELECT t.staff_name,t.gender,t.dept_code,t.post_salary,
  2. MIN(t.post_salary) KEEP(DENSE_RANK FIRST ORDER BY t.dept_code) OVER(PARTITION BY t.gender) first_value1,
  3. MAX(t.post_salary) KEEP(DENSE_RANK FIRST ORDER BY t.dept_code) OVER(PARTITION BY t.gender) first_value2,
  4. MIN(t.post_salary) KEEP(DENSE_RANK LAST ORDER BY t.dept_code) OVER(PARTITION BY t.gender) last_value1,
  5. MAX(t.post_salary) KEEP(DENSE_RANK LAST ORDER BY t.dept_code) OVER(PARTITION BY t.gender) last_value2
  6. FROM demo.t_staff t
  7. ORDER BY t.gender,t.dept_code;

2.3、数据分布类函数

  • RATIO_TO_REPORT(expr):计算当前行的值与组中所有行的值之和的比率。
  • NTILE(expr):将一组有序的数据集分为若干桶,并为每一行分配相应的桶编号。expr 必须是能被解析成正整数的值或表达式,如果带小数,小数部分将被截取。桶编号从 1 开始到 TRUNC(expr),每桶的数据行数最多相差 1。如果行数不能被桶数整除,那么靠前的桶将优先被填充,靠后的桶则会少一行数据。例如 expr=3,行数=16,则桶编号为 1 的有 6 行,桶编号为 2 或 3 的有 5 行。
  • CUME_DIST():计算一组值的累计分布,并返回大于 0、小于或等于 1 的数,该数表示该行在组中的相对位置,值相等的相邻行会得到相同的累计分布值。
  • PERCENT_RANK():与 CUME_DIST 函数类似,每行的值等于该行的行号先减去 1,再除以组中总行数减去 1,因此返回值总是大于或等于 0、小于或等于 1。
  • PERCENTILE_DISC(expr):返回一个与分布百分比想对应的数值,分布百分比的计算方法参见 CUME_DIST 函数(计算时 NULL 会被忽略)。
  • PERCENTILE_CONT(expr):返回一个与分布百分比想对应的数值,分布百分比的计算方法参见 PERCENT_RANK 函数(计算时 NULL 会被忽略)。
  • REGR_ (Linear Regression) Functions:这些线性回归函数适合最小二乘法回归线,共有 9 个不同的回归函数。
    • REGR_SLOPE:返回斜率。相当于 COVAR_POP(expr1, expr2) / VAR_POP(expr2)。
    • REGR_INTERCEPT:返回回归线的 y 截距。相当于 AVG(expr1) - REGR_SLOPE(expr1, expr2) * AVG(expr2)。
    • REGR_COUNT:返回用于填充回归线的非空数字对的数目。
    • REGR_R2:返回回归线的决定系数。如果 VAR_POP(expr2) = 0,则为 NULL;如果 VAR_POP(expr1) = 0 且 VAR_POP(expr2) != 0,则为 1;如果 VAR_POP(expr1) > 0 且 VAR_POP(expr2) != 0,则为 POWER(CORR(expr1,expr),2)。
    • REGR_AVGX:计算回归线自变量 (expr2) 的平均值。在去掉空对 (expr1,expr2) 后,相当于 AVG(expr2)。
    • REGR_AVGY:计算回归线应变量 (expr1) 的平均值。在去掉空对 (expr1,expr2) 后,相当于 AVG(expr1)。
    • REGR_SXX:在去掉空对 (expr1,expr2) 后,相当于 REGR_COUNT(expr1, expr2) * VAR_POP(expr2)。
    • REGR_SYY:在去掉空对 (expr1,expr2) 后,相当于 REGR_COUNT(expr1, expr2) * VAR_POP(expr1)。
    • REGR_SXY:在去掉空对 (expr1,expr2) 后,相当于 REGR_COUNT(expr1, expr2) * COVAR_POP(expr1, expr2)。

示例 1:

  1. SELECT t.staff_name,t.dept_code,t.post_salary,
  2. RATIO_TO_REPORT(t.post_salary) OVER() ratio_to_report,
  3. NTILE(3) OVER(ORDER BY t.dept_code,t.post_salary) ntile,
  4. CUME_DIST() OVER(ORDER BY t.dept_code,t.post_salary) cume_dist,
  5. PERCENT_RANK() OVER(ORDER BY t.dept_code,t.post_salary) percent_rank
  6. FROM demo.t_staff t
  7. ORDER BY t.dept_code,t.post_salary;

示例 2:

  1. SELECT t.staff_name,t.dept_code,t.post_salary,
  2. RATIO_TO_REPORT(t.post_salary) OVER(PARTITION BY t.dept_code) ratio_to_report,
  3. NTILE(3) OVER(PARTITION BY t.dept_code ORDER BY t.dept_code,t.post_salary) ntile,
  4. CUME_DIST() OVER(PARTITION BY t.dept_code ORDER BY t.dept_code,t.post_salary) cume_dist,
  5. PERCENT_RANK() OVER(ORDER BY t.dept_code,t.post_salary) percent_rank,
  6. PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY t.post_salary) OVER(PARTITION BY t.dept_code) percentile_disc,
  7. PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY t.post_salary) OVER(PARTITION BY t.dept_code) percentile_cont
  8. FROM demo.t_staff t
  9. ORDER BY t.dept_code,t.post_salary;

2.4、统计分析类函数

  • CORR(expr1, expr2):返回一对数的相关系数。相当于COVAR_POP(expr1, expr2) / (STDDEV_POP(expr1) * STDDEV_POP(expr2))
  • COVAR_POP(expr1, expr2):返回一对数总体协方差。相当于(SUM(expr1 * expr2) - SUM(expr2) * SUM(expr1) / n) / n
  • COVAR_SAMP(expr1, expr2):返回一对数的样本协方差。相当于(SUM(expr1 * expr2) - SUM(expr1) * SUM(expr2) / n) / (n-1)
  • STDDEV([DISTINCT | ALL] expr):计算当前行关于组的标准偏离。
  • STDDEV_POP(expr):计算总体标准差,并返回总体方差的平方根。与 VAR_POP 函数的平方根相同。
  • STDDEV_SAMP(expr):计算累积样本标准偏差,并返回样本方差的平方根。与 VAR_SAMP 函数的平方根相同。
  • VAR_POP(expr):返回非空(即忽略 NULL)数对的总体方差。
  • VAR_SAMP(expr):返回非空(即忽略 NULL)数对的样本方差。
  • VARIANCE([ DISTINCT | ALL ] expr):如果 expr = 1,则返回 0;如果 expr > 1,则返回 VAR_SAMP。

3、补充案例

案例 1,逐行累加(在实现诸如冲销、抵扣之类的功能时,该案例的写法非常有用):

  1. WITH t AS(
  2. SELECT 1 val FROM DUAL UNION ALL
  3. SELECT 3 FROM DUAL UNION ALL
  4. SELECT 5 FROM DUAL UNION ALL
  5. SELECT 7 FROM DUAL UNION ALL
  6. SELECT 9 FROM DUAL
  7. )
  8. SELECT t.val,
  9. SUM(t.val) OVER(ORDER BY ROWNUM ROWS UNBOUNDED PRECEDING) cur_sum_val,
  10. SUM(t.val) OVER(ORDER BY ROWNUM ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) pre_sum_val
  11. FROM t;

结果:

  1. VAL CUR_SUM_VAL PRE_SUM_VAL
  2. ---------- ----------- -----------
  3. 1 1
  4. 3 4 1
  5. 5 9 4
  6. 7 16 9
  7. 9 25 16

案例 2,取 A、B 两级中数值最小的行(在实现阶段性进度计划统计分析报表时,该案例的写法非常有用):

  1. WITH t AS(
  2. SELECT 'A' grade, 1 val FROM DUAL UNION ALL
  3. SELECT 'A',3 FROM DUAL UNION ALL
  4. SELECT 'A',5 FROM DUAL UNION ALL
  5. SELECT 'B',7 FROM DUAL UNION ALL
  6. SELECT 'B',9 FROM DUAL
  7. )
  8. SELECT t2.grade,t2.val FROM(
  9. SELECT t.grade,t.val,RANK() OVER(PARTITION BY t.grade ORDER BY val) rank FROM t
  10. ) t2 WHERE t2.rank=1;

结果:

  1. GRADE VAL
  2. ----- ----------
  3. A 1
  4. B 7

案例 3,查出各部门最年长和最年轻的员工信息:

  1. SELECT DISTINCT t1.dept_code,t2.enum_name dept_name,
  2. FIRST_VALUE(t1.staff_name) OVER(PARTITION BY t1.dept_code ORDER BY t1.birthday) max_older_name,
  3. FIRST_VALUE(t1.staff_name) OVER(PARTITION BY t1.dept_code ORDER BY t1.birthday DESC) min_young_name
  4. FROM demo.t_staff t1
  5. LEFT JOIN demo.t_field_enum t2 ON t2.field_code='DEPT' AND t1.dept_code=t2.enum_code
  6. ORDER BY t1.dept_code; -- 注意:此处一旦用了 DISTINCTORDER BY 列表中的字段就必须是 SELECT 列表中出现过的

结果:

  1. DEPT_CODE DEPT_NAME MAX_OLDER_NAME MIN_YOUNG_NAME
  2. ------------------------ ---------------------------- ---------------------------- ---------------------------
  3. 010101 研发一部 小明 王二
  4. 010102 研发二部 小萨 小林
  5. 010103 研发三部 韩三 小玲
  6. 010104 测试部 小梅 小燕
  7. 010201 实施一部 小军 小红
  8. 010202 实施二部 小飞 小飞

总结

严格来说本文应该算是分析函数的入门篇,因为只讲述了分析函数的语法和简单用法。尽管窗口规则比较多,但只要稍作分析,就会发现其实并不复杂,重点是要能结合实际情况灵活运用。最好的参考就是补充案例一,我本人当初也是在网上看到一条类似补充案例一中的 SQL 语句后才开始我的分析函数之旅的!巧的是没过多久公司财务要求在报销流程中增加智能冲销功能,恰好用上!

本文列出了 Oracle 10g 中的所有分析函数。其中普通统计类函数和数据排序类函数我用过一些,因为除了解释函数用途还给出了一些示例。但数据分布类函数和统计分析类函数大多只给出了简单的释义,主要是因为在日常开发中极少用到,而且大部分我也从没用过。如果你想进一步了解的话请参考官方手册:Analytic Functions

本文链接http://www.cnblogs.com/hanzongze/p/oracle-over.html

版权声明:本文为博客园博主 韩宗泽 原创,作者保留署名权!欢迎通过转载、演绎或其它传播方式来使用本文,但必须在明显位置给出作者署名和本文链接!本人初写博客,水平有限,若有不当之处,敬请批评指正,谢谢!

.Net程序员学用Oracle系列(22):分析函数(OVER)的更多相关文章

  1. .Net程序员学用Oracle系列(9):系统函数(上)

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.字符函数 1.1.字符函数简介 1.2.语法说明及案例 2.数字函数 2.1.数字函数简介 2.2.语法说明及案例 3.日期 ...

  2. .Net程序员学用Oracle系列(1):导航目录

    本人从事基于 Oracle 的 .Net 企业级开发近三年,在此之前学习和使用的都是 (MS)SQL Server.未曾系统的了解过 Oracle,所以长时间感到各种不习惯.不方便.怪异和不解,常会遇 ...

  3. .Net程序员学用Oracle系列(2):准备测试环境

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.创建说明 1.1.为什么要创建的测试环境? 1.2.了解 Oracle 实例的默认用户 2.创建环境 2.1.创建基本环境 ...

  4. .Net程序员学用Oracle系列(6):表、字段、注释、约束、索引

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.表 1.1.创建表 1.2.修改表 & 删除表 2.字段 2.1.添加字段 2.2.修改字段 & 删除字段 ...

  5. .Net程序员学用Oracle系列(7):视图、函数、过程、包

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.视图 1.1.创建视图 2.函数 2.1.创建函数 2.2.调用函数 3.过程 3.1.创建过程 3.2.调用过程 4.包 ...

  6. .Net程序员学用Oracle系列(8):触发器、任务、序列、连接

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.触发器 1.1.创建触发器 1.2.禁用触发器 & 启用触发器 & 删除触发器 2.任务 2.1.DBMS_ ...

  7. .Net程序员学用Oracle系列(10):系统函数(下)

    <.Net程序员学用Oracle系列:导航目录> 本文大纲 1.转换函数 1.1.TO_CHAR 1.2.TO_NUMBER 1.3.TO_DATE 1.4.CAST 2.近似值函数 2. ...

  8. .Net程序员学用Oracle系列(11):系统函数(下)

    1.聚合函数 1.1.COUNT 函数 1.2.SUM 函数 1.3.MAX 函数 1.4.MIN 函数 1.5.AVG 函数 2.ROWNUM 函数 2.1.ROWNUM 函数简介 2.2.利用 R ...

  9. .Net程序员学用Oracle系列(15):DUAL、ROWID、NULL

    1.DUAL 表 2.ROWID 类型 2.1.利用 ROWID 查询数据 2.2.利用 ROWID 更新数据 3.NULL 值 3.1.NULL 与空字符串 3.2.NULL 与函数 3.3.NUL ...

随机推荐

  1. Bootstrap入门(三)<p>标签的css样式

    Bootstrap入门(三)<p>标签的css样式 前提:引入css文件,内容放在一个class为container的div中   <p>标签属性 1.“ text-left ...

  2. node源码详解(四) —— js代码如何调用C++的函数

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource4 本博客同步在https://cnodejs.o ...

  3. page cache 与free

    我们经常用free查看服务器的内存使用情况,而free中的输出却有些让人困惑,如下: 先看看各个数字的意义以及如何计算得到: free命令输出的第二行(Mem):这行分别显示了物理内存的总量(tota ...

  4. Linux Platform驱动模型(一)-设备信息

    我在Linux字符设备驱动框架一文中简单介绍了Linux字符设备编程模型,在那个模型中,只要应用程序open()了相应的设备文件,就可以使用ioctl通过驱动程序来控制我们的硬件,这种模型直观,但是从 ...

  5. [html5] 学习笔记-html5增强的页面元素

    在 HTML5 中,不仅增加了很多表单中的元素,同时也增加和改良了可以应用在整个页面中的元素.重点包含 figure.figcaption.details.summary.mark.progress. ...

  6. tableView的总结

    // // ViewController.m // TableViewController // // Created by 王妍 on 16/3/23. // Copyright © 2016年 c ...

  7. jvm的内存空间分区

    在方法(代码块)中定义一个变量时,java就在栈中为这个变量分配JVM内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的JVM内存空间:而在堆中分配的JVM内存由java虚拟机的自动 ...

  8. Java String类和Object类

    String类: 方法: 1.charAt(int index):取index下标的char类型值 2.endsWith(String prefix) /startsWith(String prefi ...

  9. 如何修改Window系统下PATH路径以及win8下masm32V11

    如何修改Window系统下PATH路径   //其实这个都是临时性的, 退出dos窗口就没有用了,只是做个笔记罢了   C:\Users\Administrator>    set path=E ...

  10. 简述.jpg .Gif .png-8 .png-24的区别

    最近有很多朋友在开发过程中有时候会遇到图片加载不清晰,透明度失真,或者对图片进行操作之后造成图片损耗的现象,在这里给大家简单介绍一下常用的几种图片格式之间的区别 Gif格式特点: 1.透明性,Gif是 ...