sql server 窗口函数

定义:

窗口函数 microsoft官方文档里面的解释为:

确定在应用关联的开窗函数之前,行集的分区和排序

窗口是用户指定的一组行。开窗函数计算从窗口派生的结果集中各行的值。可以在单个查询中将多个排名或聚合开窗函数与单个 FROM 子句一起使用。但是,每个函数的 OVER 子句在分区和排序上可能不同。OVER 子句不能与 CHECKSUM 聚合函数结合使用

开始看的时候我不是很理解,自己测试完以后勉强能够看懂吧。写的不对的地方请大家指正。窗口函数和聚合函数的功能类似,都可以对某一列的值进行计算。但不同的是聚合函数必须配合 group by 使用,来显示分组之后组集和组集的聚合值,而窗口函数不需要 分组 就可以显示所有结果集和某些组集的聚合值

例如:我们查询学生姓名,平均成绩的话 直接用AVG(成绩) 然后根据姓名分组就可以了,如果我们希望再加一列课程名和每门课程所有同学的平均分呢,是不是一句话就搞不定了。这时候窗口函数就派上用长了。

窗口函数分类:

SQL Server 提供排名开窗函数和聚合开窗函数

1、聚合开窗函数   :聚合开窗函数不能与order by 一起使用

2、排名开窗函数

 

(1)、聚合开窗函数: 配合聚合函数来使用

例:

测试表没有遵循范式:

if exists (select 1 from tempdb.dbo.sysobjects where name='##test')
drop table ##test

--创建测试表
create table ##test (
  id int identity(1,1),
  name varchar(8)     ,
  branch varchar(10)  ,
  wage  numeric(9,2)
)
--插入十条数据
insert into ##test values ('张三','销售部',2500)
insert into ##test values ('李四','销售部',3000)
insert into ##test values ('王五','行政部',2000)
insert into ##test values ('孙六','行政部',2300)

insert into ##test values ('赵八','市场部',2600)
insert into ##test values ('张九','市场部',3000)

insert into ##test values ('李十','后勤部',2500)
insert into ##test values ('刘十一','后勤部',3000)

insert into ##test values ('懂十二','后勤部',2500)
insert into ##test values ('孙十三','基建部',3000)

select * from ##test

 

 

1、我们现在想要查询 员工的姓名,所在部门,工资,所在部门的平均工资

select name,branch,wage,AVG(wage) over (partition by branch)as 部门平均工资 from ##test

我理解的他的逻辑语意是这样的,根据 branch列来分区 计算每个分区的平均工资,partition by 可以指定根据多列来分区,也可以不带partition by 不写的话整张表就是一个区

结果:

跟其他聚合函数配合的结果:

select name,branch,wage,AVG(wage) over (partition by branch)as 部门平均工资
,COUNT(branch) over (partition by branch) as 部门人数
,SUM(wage) over (partition by branch)as 部门工资总数
 from ##test
 go
View Code

 

如果不用窗口函数也可以实现但是 查询性能不如运用窗口函数。

 

 select name,branch,wage,(select AVG(wage) from ##test a where a.branch=b.branch) as 部门平均工资
 ,(select COUNT(name) from ##test c where c.branch=b.branch ) as 部门人数
 ,(select SUM(wage) from ##test d where d.branch=b.branch) as 部门工资总数
   from ##test b
View Code

 

理解的不是太深刻,也请各位砖家表笑我,多多拍砖

 

.......排名函数  :

sql server 2008 提供了4个排名函数

1、row_number()

2、rank()

3、dense_rank()

4、ntile()

row_number()

row_number()函数语法为:

 

ROW_NUMBER ( )     OVER ( [ <partition_by_clause> ] <order_by_clause> )
 

 

 

作用是对来自from 的结果集中根据某一列或者多列的值进行排序然后对结果集加编号,编号从整数1开始,如不指定partition 分区那么将对所有结果集当成一个区进行排序编号,如果指定分区,那么将结果按照partition by 的字段分为一个或者多个区,每一个被当成一个集合,对每一个集合分别排序编号。

row_number 函数常用于分页查询中。在2008之前分页查询是用 top和反top的方法,2008增加row函数之后分页查询变得简单了许多

例:

现有结果集:

 

图(1)

用row_number () 来对结果集编号:

select ROW_NUMBER() over (order by je asc )as bh,SFMC,JE from JK_MZMX

图(2)

我们再根据sfmc列把结果集分区后编号:

select ROW_NUMBER() over (partition by sfmc order by je asc )as bh,SFMC,JE from JK_MZMX

图(3)

注意上图我标蓝的地方,je字段的值是相同的,但是编号不同,假如我们要把一次考试的成绩来进行排名,如果同学A和B都考了100分那么肯定是并列第一,那这时候需要用到dense_rank()函数了

rank() 和dense_rank()函数

这两个函数和row_number()函数的功能类似都是对结果集按照排序列进行编号但是不同的是:RANK 和 DENSE_RANK 向在排序列中具有相同值的行分配相同的排序

还是图三的写法,把row_number()分别换成rank()和dense_rank()函数来试验一下

select rank() over (partition by sfmc order by je asc )as bh,SFMC,JE from JK_MZMX

rank()函数把排序列相同的记录编号也给予相同的编号,可是排序列的值晋升一阶后编号怎么变成7了,因为rank()函数是返回结果集分区内每行的排名,行的排名是相关行之前排名数加1,所以7表示的是第七行。看来rank()函数还是不能满足上边说的对成绩排名的需求

试试dense_rank()

select dense_rank() over (partition by sfmc order by je asc )as bh,SFMC,JE from JK_MZMX

 

因为dense_rank()函数是返回结果集中分区的排名,但是排名不间断,行排名是上一个排名数+1而不是上一行数+1.

NTILE()

 

转载于:https://www.cnblogs.com/dong139/p/5073793.html

### SQL Server 窗口函数概述 SQL Server窗口函数是一种强大的工具,能够对查询结果中的数据子集执行复杂计算而无需依赖子查询或临时表[^3]。通过定义一个逻辑上的“窗口”,可以在该范围内应用各种排名、聚合或其他类型的计算。 --- ### 常见的窗口函数分类及功能说明 #### 1. **排名函数** 排名函数用于分配唯一的编号给每一行,或者按照特定条件分组并排序后的每组内的行数。 - `ROW_NUMBER()`:为分区内的每一行生成唯一序号。 - `RANK()` 和 `DENSE_RANK()`:分别为相同值的行赋予相同的排名,但它们处理重复的方式不同——`RANK()`会跳过后续排名,而`DENSE_RANK()`不会。 以下是使用 `ROW_NUMBER()` 的示例: ```sql SELECT EmployeeID, DepartmentID, Salary, ROW_NUMBER() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) AS RowNum FROM Employees; ``` 此语句按部门 (`DepartmentID`) 对员工薪资降序排列,并为其分配连续的行号[^1]。 对于 `RANK()` 或 `DENSE_RANK()` 可以这样实现: ```sql SELECT EmployeeID, DepartmentID, Salary, RANK() OVER (PARTITION BY DepartmentID ORDER BY Salary DESC) AS RankValue FROM Employees; ``` --- #### 2. **聚合函数** 这类函数允许在不减少原始记录数量的情况下完成统计运算。 - 支持的标准聚合操作有 `SUM()`、`AVG()`、`COUNT()`、`MIN()` 和 `MAX()` 等。 例如,在订单明细表中累计销售额: ```sql SELECT OrderID, ProductID, Quantity, UnitPrice, SUM(Quantity * UnitPrice) OVER (ORDER BY OrderID) AS RunningTotalSales FROM OrderDetails; ``` 上述脚本展示了如何利用累积求和来跟踪销售总额的变化趋势[^2]。 --- #### 3. **偏移函数** 偏移类函数帮助访问当前行之前或之后的数据项。 - 主要成员包括 `LAG()` 和 `LEAD()` ,分别获取前驱与后继行的内容。 假设我们想比较某一天与其前一天的价格变动情况,则可编写如下代码片段: ```sql SELECT Date, StockPrice, LAG(StockPrice, 1) OVER (ORDER BY Date) AS PreviousDayPrice, StockPrice - LAG(StockPrice, 1) OVER (ORDER BY Date) AS PriceChange FROM DailyPrices; ``` 这里运用了 `LAG()` 函数读取紧邻日期对应的股价信息以便进一步分析差额变化。 --- ### 总结语法结构 基本形式遵循以下模式: ```sql <window_function> (<expression>) OVER ( [ PARTITION BY <partition_expression_list> ] [ ORDER BY <order_by_expression_list> ] [ window_frame_clause ] ) ``` 其中 `<window_function>` 是指具体使用的窗口函数名称;`OVER (...)` 子句用来指定划分依据以及排序规则等细节参数设置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值