窗口函数也称为 OLAP (OnLine Analytical Processing)函数,意思是对数据库数据进行实时分析处理。例如,市场分析、创建财务报表、创建计划等日常性商务工作
<窗口函数> OVER ([PARTITION BY <列清单>] ORDER BY <排序用列清单>) ※[]中的内容可以省略
■能够作为窗口函数使用的函数 ① 能够作为窗口函数的聚合函数(SUM、AVG、COUNT、MAX、MIN) ② RANK、DENSE_RANK、ROW_NUMBER 等专用窗口函数
PARTITION BY 能够设定排序的对象范围 ORDER BY 能够指定按照哪一列、何种顺序进行排序
窗口函数兼具 GROUP BY 子句的分组功能以及ORDER BY 子句的排序功能。但是,PARTITION BY 子句并不具备GROUP BY 子句的汇总功能
通过 PARTITION BY 分组后的记录集合称为窗口。此处的窗口并非“窗户”的意思,而是代表范围
●RANK函数 计算排序时,如果存在相同位次的记录,则会跳过之后的位次。 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、4 位……
●DENSE_RANK函数 同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。 例)有 3 条记录排在第 1 位时:1 位、1 位、1 位、2 位……
●ROW_NUMBER函数 赋予唯一的连续位次。 例)有 3 条记录排在第 1 位时:1 位、2 位、3 位、4 位……
-- 比较RANK、DENSE_RANK、ROW_NUMBER的结果 select product_name,product_type,sale_price, rank() over ( order by sale_price) as ranking, dense_rank () over ( order by sale_price) as dense_ranking, row_number () over ( order by sale_price) as row_num from product;由于专用窗口函数无需参数,因此通常括号中都是空的
原则上窗口函数只能在SELECT子句,ORDER BY子句或者UPDATE语句的SET子句中使用 原因:在 DBMS 内部,窗口函数是对 WHERE 子句或者 GROUP BY 子句处理后的“结果”进行的操作
以“自身记录(当前记录)”作为基准进行统计,就是将聚合函数当作窗 口函数使用时的最大特征
窗口函数就是将表以窗口为单位进行分割,并在其中进行排序的函数。其实其中还包含在窗口中指定更加详细的汇总范围的备选功能,该备选功能中的汇总范围称为框架
-- 指定“最靠近的3行”作为汇总对象 select product_id,product_name,sale_price, avg(sale_price) over ( order by product_id rows 2 preceding) as moving_avg -- 截止到之前2行 from product;●指定框架(汇总范围) 截止到之前2行: ● 自身(当前记录) ● 之前1行的记录 ● 之前2行的记录
**移动平均(moving average)在希望实时把握“最近状态”**时非常方便,因此常常会应用在对股市趋势的实时跟踪当中
-- 将当前记录的前后行作为汇总对象 select product_id,product_name,sale_price, avg(sale_price) over ( order by product_id rows between 1 preceding and 1 following) as moving_avg from product;使用窗口函数时必须要在 OVER 子句中使用ORDER BY,OVER 子句中的ORDER BY 只是用来决定窗口函数按照什么样的顺序进行计算的,对结果的排列顺序并没有影响
-- 在语句末尾使用ORDER BY子句对结果进行排序 select product_name,product_type,sale_price, rank() over ( order by sale_price) as ranking from produc order by ranking;GROUPING 运算符包含以下 3 种: ●ROLLUP ●CUBE ●GROUPING SETS
■ROLLUP的使用方法
-- 使用ROLLUP同时得出合计和小计 select product_type, sum(sale_price) as sum_price from product group by product_type with rollup;一次计算出不同聚合键组合的结果: ① GROUP BY () 超级分组记录(默认使用NULL作为聚合键):相当于没有 GROUP BY子句(这时会得到全部数据的合计行的记录) ② GROUP BY (product_type)
-- 在GROUP BY中添加“登记日期” select product_type, sum(sale_price) as sum_price from product group by product_type,regist_dat with rollup;① GROUP BY () ② GROUP BY (product_type) ③ GROUP BY (product_type, regist_date)
GROUPING 函数在其参数列的值为超级分组记录所产生的 NULL 时返回 1,原始数据为NULL时返回 0
-- 使用GROUPING函数来判断NULL select grouping(product_type) as product_type,grouping(regist_date) as regist_date,sum(sale_price) as sum_price from product group by product_type,regist_dat with rollup; -- 在超级分组记录的键值中插入恰当的字符串 select case when grouping(product_type) = 1 then '商品种类 合计' else product_type end as product_type, case when grouping(regist_date) = 1 then '登记日期 合计' else cast(regist_date as varchar(16)) /* 为什么还要将 SELECT 子句中的 regist_date 列转换为 CAST(regist_date AS VARCHAR(16))形式的字符串呢? 这是为了满足 CASE 表达式所有分支的返回值必须一致的条件 */ end as regist_date, sum(sale_price) as sum_price from product group by product_type, regist_date with rollup;① GROUP BY () ② GROUP BY (product_type) ③ GROUP BY (regist_date) ←添加的组合 ④ GROUP BY (product_type, regist_date)
组合的个数是 2^n(n 是聚合键的个数) 使用ROLLUP时组合的个数是n + 1
可以把CUBE理解为将使用聚合键进行切割的模块堆积成一个立方体