10、SQL Server 基础 - SELECT中开窗函数与OVER子句

一组行称为一个窗口,开窗函数是可以用于分区计算的函数,分为聚合函数排名函数,分别可以放在OVER子句前以对组内的数据进行编号和运算。
注:本节”窗”就是指”分区”。

聚合函数与OVER子句

聚合函数是对一组值执行计算并返回单一的值的函数。如SUM()、AVG()、MIN()、MAX()。

 SELECT 列名表,
    聚合函数(参数列名) OVER(PARTITION BY 分区依据列) AS '生成列名',
    聚合函数(参数列名) OVER(PARTITION BY 分区依据列) AS '生成列名',
    ...
    聚合函数(参数列名) OVER(PARTITION BY 分区依据列) AS '生成列名'
FROM 表名

例如:

 select Cno,CName,Semester,Credit,
    SUM(Credit) over(partition by Semester) as '学期总学分',
    AVG(Credit) over(partition by Semester) as '平均学分',
    MIN(Credit) over(partition by Semester) as '最小学分',
    MAX(Credit) over(partition by Semester) as '最大学分'
from Course

又如:

 select OrderID 订单号,ProductID 产品号,Num 订购数量,
    SUM(Num) over(partition by ProductID) AS '该类产品共订了',
    CAST(
        1.0*Num/
        (SUM(Num) over(partition by ProductID))
        *100
        as decimal(5,2)
        ) AS '所占百分比'
from OrderTab

排名函数与OVER子句

排名函数是为分区中的每一行返回一个排名值的函数。SQL Server中的排名函数有:RANK()、DENSE_RANK()、NTILE、ROW_NUMBER。

①RANK()、DENSE_RANK()、ROW_NUMBER函数
这三个函数功能类似,都是对分区后的窗按一个排序依据列内排序,并生成新的列,它们的语法也一致:

 SELECT 列名表,
    函数名() OVER(PARTITION BY 分区依据列
            ORDER BY 排序依据列 [DESC]) AS '生成列名',
    函数名() OVER(PARTITION BY 分区依据列
            ORDER BY 排序依据列 [DESC]) AS '生成列名',
    ...
    函数名() OVER(PARTITION BY 分区依据列
            ORDER BY 排序依据列 [DESC]) AS '生成列名'
FROM 表名
[ORDER BY 有时需以分区依据列做外排 [DESC]]

例如:

 select OrderID 订单号,ProductID 产品号,Num 订购数量,
    RANK() over(partition by ProductID 
                order by Num desc) AS 'RANK排名列',
    DENSE_RANK() over(partition by ProductID 
                order by Num desc) AS 'DENSE_RANK排名列',
    ROW_NUMBER() over(partition by ProductID 
                order by Num desc) AS 'ROW_NUMBER排名列'
from OrderTab

②NTILE()函数
尝试等分成几块,并生成新的列:

 SELECT 列名表,
    NTILE(划分块数) OVER([PARTITION BY 如果需分窗分别处理此处应指定]
            ORDER BY 排序依据列 [DESC]) AS '生成列名'
FROM 表名
[ORDER BY 有时可以根据需求做外排 [DESC]]

这个函数用得很少,它会尽量尝试等分,注意不使用OVER内的PATTERN BY时,它就与开窗无关了,仅仅是做整体性的尝试等分。

例如:

 select OrderID 订单号,ProductID 产品号,Num 订购数量,
    NTILE(4) over(order by Num desc) AS 'NTILE划分列'
from OrderTab