• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Brambling
博客园    首页    新随笔    联系   管理    订阅  订阅

SQL Server排名函数与排名开窗函数

什么是排名函数?说实话我也不甚清楚,我知道 order by 是排序用的,那么什么又是排名函数呢?

接下来看几个示例就明白了。

首先建立一个表,随便插入一些数据。

ROW_NUMBER 函数:直接排序,ROW_NUMBER函数是以上升进行直接排序,并且以连续的顺序给每一行数据一个唯一的序号。(即排名连续)

1 -- 以下是根据 U_Pwd 这一列进行排名(升序)
2 select *,
3 '第'+convert(varchar,ROW_NUMBER() over(order by U_Pwd))+'名' RowNum
4 from UserInfo

RANK 函数:并列排序,在 order by 子句中指定的列,如果返回一行数据与另一行具有相同的值,rank函数将给这些行赋予相同的排名数值。

在排名的过程中,保持一个内部计数值,当值有所改变时,排名序号将有一个跳跃。(即排名不连续)

1 -- 以下是根据 U_Pwd 这一列进行排名(升序)
2 select *,
3 '第 '+convert(varchar,rank() over(order by U_Pwd))+' 名' RowNum
4 from UserInfo

可以明确的看到有4行数据并列第2名,然后直接就是第6名,这是因为 order by 子句中指定的列 U_Pwd 的值相同。

DENSE_RANK 函数:并列排序,这一点与 RANK() 函数类似,order by 子句指定的列的值相同,排名数值相同,但是后面是连续的。(即排名连续)

1 -- 以下是根据 U_Pwd 这一列进行排名(升序)
2 select *,
3 '第 '+convert(varchar,DENSE_RANK() over(order by U_Pwd))+' 名' RowNum
4 from UserInfo

可以看到即使有4行数据并列第2名,但是接下来依然是第3名。

NTILE 函数:将查询的结果分发到指定数量的组中。 各个组有编号,编号从1开始。 对于每一行,NTILE 将返回此行所属的组的编号。

组中的行数计算方式为 total_num_rows(结果集的总行数) / num_groups(指定的组数)。

如果有余数 n,则前面 n 个组获得一个附加行。因此,可能不会所有组都获得相等数量的行,但是组大小最大只可能相差一行。

例如,如果总行数是 53,组数是 5,53 / 5 等于10余数是3,按上面个规则就是,每组分配10行,又因余数为3,所以前面3组每组附加一行。

则前三个组每组包含 11 行,其余两个组每组包含 10 行。

另一方面,如果总行数可被组数整除,则行数将在组之间平均分布。 例如,如果总行数为 50,有五个组,则每组将包含 10 行。

1 -- 以下是根据 U_Pwd 这一列进行分组
2 select *,
3 '第 '+convert(varchar,NTILE(3) over(order by U_Pwd))+' 组' RowNum
4 from UserInfo

这个表中有10条数据,指定分为3组,10/3等于3余数1。

PS:排名函数后面必须有 over() 子句。

 

排名开窗函数:

ROW_NUMBER、DENSE_RANK、RANK、NTILE属于排名函数,OVER()就是窗口函数。

窗口函数OVER()指定一组行,开窗函数计算从窗口函数输出的结果集中各行的值。

开窗函数不需要使用GROUP BY就可以对数据进行分组,还可以同时返回基础行的列和聚合列。

排名开窗函数可以单独使用ORDER BY 语句,也可以和PARTITION BY同时使用。

ODER BY 指定排名开窗函数的顺序。在排名开窗函数中必须使用ORDER BY语句。

PARTITION BY用于将结果集进行分组,开窗函数应用于每一组。

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,ROW_NUMBER() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因为 U_Pwd 这一列有4种不同的值,所以分为4组,然后 ROW_NUMBER 再在每一组中进行连续排序。

 

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,rank() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因为 U_Pwd 这一列有4种不同的值,所以同样是分为4组,然后 RANK 再在每一组中进行排序,因为RANK是并列排序,所以全部都是第一名。下面换个字段排序试试看。

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 U_Name 排序
2 select *,
3 '第'+convert(varchar,rank() over(partition by U_Pwd order by U_Name))+'名' RowNum
4 from UserInfo

 

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 U_Pwd 排序
2 select *,
3 '第'+convert(varchar,DENSE_RANK() over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因为 U_Pwd 这一列有4种不同的值,所以同样是分为4组,然后 DENSE_RANK 再在每一组中进行排序,因为DENSE_RANK也是并列排序,所以全部都是第一名。下面换个字段排序试试看。

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 U_Name 排序
2 select *,
3 '第'+convert(varchar,DENSE_RANK() over(partition by U_Pwd order by U_Name))+'名' RowNum
4 from UserInfo

 

1 -- 以下是先根据 U_Pwd 这一列进行分组,然后每一组再根据 NTILE(3) 指定的组数分组,最后在根据 order by 子句指定的字段 U_Pwd 排序 
2 select *,
3 '第'+convert(varchar,NTILE(3) over(partition by U_Pwd order by U_Pwd))+'名' RowNum
4 from UserInfo

因为 U_Pwd 这一列有4种不同的值,所以同样是分为4组。第1组有1条数据,所以就1个区。第2组有4条数据,4/3等于1余数1,所以第2组分为3个区,又因余数为1,所以第1个区附加1行。第3组有3条数据,3/3等于1余数为0,所以第3组有3个区。第4组有2条数据,所以分为2个区。

PS:在排序开窗函数中使用 PARTITION BY 子句需要放置在 ORDER BY子句之前。

 

参考:

http://www.cnblogs.com/jhxk/articles/2531595.html

posted @ 2017-04-14 02:01  Brambling  阅读(4445)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3