【译】高级T-SQL进阶系列 (七)【下篇】:使用排序函数对数据进行排序
此文为翻译,由于本人水平有限,疏漏在所难免,欢迎探讨指正。
原文链接:传送门。
使用NTILE函数的示例
NTILE函数将一组记录分割为几个组。其返回的分组数是由一个整形表达式指定的。如下你会找到NTILE函数的句法格式:
NTILE (integer_expression) OVER ( [ PARTIION BY <partition_column> ] ORDER BY <order_by_column> )
其中:
- <integer_expression>:指定了将要创建的不同分组的数目
- <partition_column>:指定了一个或者多个列名,其将用来对数据进行分区
- <order by column>: 指定了一个或者多个列名,其将用来对各个分区的输出进行排序
为了更好的理解NTILE函数是做什么的,让我们来查看一些不同的例子。
对于第一个例子,我们假设你想将每一个PostalCode归为两个分组中的一个。为了满足这个需求,我将运行在列表4的代码中的NTILE函数:
USE AdventureWorks2012;
GO
SELECT PostalCode, StateProvinceID,
NTILE(2) OVER
(ORDER BY PostalCode ASC) AS NTileValue
FROM Person.Address
WHERE StateProvinceID IN (23,46);
列表4:NTILE查询
当我运行列表4的代码,我将得到结果4的结果:
PostalCode StateProvinceID NTileValue
--------------- --------------- --------------------
03064 46 1
03064 46 1
03106 46 1
03276 46 1
03865 46 1
83301 23 2
83402 23 2
83501 23 2
83702 23 2
83864 23 2
结果4:从运行列表4的代码产生的输出
通过查看结果4的输出,你可以看到会有两个不同的NTileValue列值,1和2。之所以有两个不同的NTileValue值被创建,是因为我在列表4的查询语句中指定了“NTILE(2)”。在紧接着NTILE函数名的括号中的值是一个整型表达式,其指定了应该被创建的分组数。如同你在结果4中看到的,有10行数据被返回。前5行具有一个NTileValue 1,后5行具有NTileValue 2。列表4中的代码按预期创建了数据行的两个分组,每组都有一半的数据行。
你或许会问自己,,如果数据行数不能被NTILE函数的interger_expression参数整除,若产生一个余数,那么情况会是怎样的?当这种情形发生时,每一个余下的行会被放置在每个分组中,从第一个分组开始,直至所有的余数行都被分配给每个分组,如同你在列表5中将会看到的那样。列表5不仅演示了当integer_expression导致了一个不平均的数据行的分配时候会发生什么,而且其还演示了如何使得integer_expression成为一个本地变量。
让我们查看列表5的代码以及结果5的输出来定义SQL SERVER 在数据行数不能被平均分给各个分组时,它是如何处理创建分组的。
USE AdventureWorks2012;
GO
DECLARE @Integer_Expression int = 4;
SELECT PostalCode, StateProvinceID,
NTILE(@Integer_Expression) OVER
(ORDER BY PostalCode ASC) AS NTileValue
FROM Person.Address
WHERE StateProvinceID IN (46,23);
列表5:带有多余记录数的NTile查询
当我运行列表5,我将得到结果5的结果。
PostalCode StateProvinceID NTileValue
--------------- --------------- --------------------
03064 46 1
03064 46 1
03106 46 1
03276 46 2
03865 46 2
83301 23 2
83402 23 3
83501 23 3
83702 23 4
83864 23 4
结果5:运行列表5产生的输出 在列表5的代码中我定义了一个名为@Integer_Expression的本地变量,并给它赋值为4。接下来在对NTile函数的调用中我使用了这个变量,指定将返回4个分组。如果你查看输出你将发现SQL SERVER创建了四个不同的分组。
当你用10除以4时,你将得到一个余数2。这意味着前两个分组应该比后两个分组多一个数据行。通过查看列表5的输出你可以确认这点。在这个输出中你将看到1组和2组都包含了3行数据,而3组和4组则只有两行数据。 和Rank函数一样,你可以通过在你的NTile函数调用中包含PARTITION BY子句来在每一个分区中创建NTILE排序值。当你在NTILE函数中添加PARTITION BY子句时,SQL SERVER会对每一个分区从1开始NTILE排序值。为了演示这个,让我来运行列表6的代码。
USE AdventureWorks2012;
GO
DECLARE @Integer_Expression int = 3;
SELECT PostalCode, StateProvinceID,
NTILE(@Integer_Expression) OVER
(PARTITION BY StateProvinceID
ORDER BY PostalCode ASC) AS NTileValue
FROM Person.Address
WHERE StateProvinceID IN (46,23);
列表6:NTile查询
当我运行列表6,我得到了结果6的输出。
PostalCode StateProvinceID NTileValue
--------------- --------------- --------------------
83301 23 1
83402 23 1
83501 23 2
83702 23 2
83864 23 3
03064 46 1
03064 46 1
03106 46 2
03276 46 2
03865 46 3
结果6:运行列表6的输出
如果你查看结果6的输出,你便能看到由于添加了PARTITION BY 子句到NTILE函数调用产生的效果。如果你查看输出列NTileValue的列值,你会发现对于StateProvinceID为46的行,它们的NTILE排序值又重新从1开始。这便是因为你在我的NTILE函数调用时添加了“PARTITION BY StateProvinceID”子句。
使用ROW_NUMBER函数的例子
有一些时候,你只想为你的输出的每一行生成一个行号,在这里,对于结果集中的每一个新行,其行号总是按顺序递增1的。为了完成这个,我们能够使用ROW_NUMBER函数。
以下是ROW_NUMBER函数的句法:
ROW_NUMBER () OVER ( [ PARTIION BY <partition_expressions> ] ORDER BY <order_by_column> )
其中:
- <partition_expressions>: 定义了一个或者多个表达式,其用来对数据进行分区
- <order by column>:定义了一个或者多个列表,其用来对各个分区的输出进行排序
为了演示ROW_NUMBER函数是如何工作的,我会运行列表7的代码:
USE AdventureWorks2012;
GO
SELECT PostalCode, StateProvinceID,
ROW_NUMBER() OVER
(ORDER BY PostalCode ASC) AS RowNumber
FROM Person.Address
WHERE StateProvinceID IN (46,23);
列表7:使用ROW_NUMBER函数
当我运行列表7,我得到了结果7的结果。
PostalCode StateProvinceID RowNumber
--------------- --------------- --------------------
03064 46 1
03064 46 2
03106 46 3
03276 46 4
03865 46 5
83301 23 6
83402 23 7
83501 23 8
83702 23 9
83864 23 10
结果7:运行列表7的代码产生的输出
通过查看结果7的输出,你将看到我的每一行数据都会有一个唯一的RowNumber列值。RowNumber列值开始于1,并且对于每一行都是按1递增。当我调用ROW_NUMBER函数时,你可以看到我仅仅指定了ORDER BY 子句。在我的示例中,我按PostalCode列进行排序,因为我没有PARTITION BY子句,ROW_NUMBER函数对于每个行返回一个不同的RowNumber值。
假设你仍然按PostalCode排序,但是你又希望对每个新的StateProvinceID,RowNumber都会从1开始,为了实现这个目的,我将给我的查询中添加PARTITION BY子句,如同我在列表8中所做的那样:
USE AdventureWorks2012;
GO
SELECT PostalCode, StateProvinceID,
ROW_NUMBER() OVER
(PARTITION BY StateProvinceID
ORDER BY PostalCode ASC) AS RowNumber
FROM Person.Address
WHERE StateProvinceID IN (46,23);
列表8:在ROW_NUMBER函数中使用PARTITION BY 子句的查询
当我运行列表8,我得到了结果8的结果
PostalCode StateProvinceID RowNumber
--------------- --------------- --------------------
83301 23 1
83402 23 2
83501 23 3
83702 23 4
83864 23 5
03064 46 1
03064 46 2
03106 46 3
03276 46 4
结果8:从运行列表8得到的输出
如同你在结果8中所看到的,通过ow向我的查询中添加PARTITION BY子句,对于每一个StateProvinceID,其RowNumber列值都会从1重新开始。
总结
我们有许多中方法对数据进行排序,并且其中一些方法需要你分配应该序列数。在本节中我向你展示了ROW_NUMBER, NTILE, RANK, DENSE_RANK是如何产生一个有序的列值的,下次当你需要产生一个有序的列值时,你应该考虑使用这些排序函数中的某一个。
问题与答案
问题1:
下列那个排序函数允许你指定一个整型表达式,其用来定义你将要使数据拆分为的分组数?
- RANK
- DENSE_RANK
- NTILE
- ROW_NUMBER
问题2:
DENSE_RANK 函数做了什么不同与RANK函数的事情?
- 当有重复值时,其产生排序值会跳过一些值
- 当有重复值时,其产生排序值不会跳过一些值
问题3:
下列哪一个子句会导致对于不同的分组排序值会从1开始?
- ORDER BY
- OVER
- PARTITION BY
答案
问题1:
正确的答案是C,NTILE函数使用提供的整型值来将你的数据分割为几个组。
问题2:
正确答案是B,当遇见重复的值时,DENSE_RANK不会跳过有序的值。
问题3:
正确答案是C,PARTITON BY子句告诉SQLSERVER 每次遇到新的分区列值返回,排序值都会从1开始。
【译】高级T-SQL进阶系列 (七)【下篇】:使用排序函数对数据进行排序的更多相关文章
- 【译】高级T-SQL进阶系列 (七)【上篇】:使用排序函数对数据进行排序
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 什么是排序函数(Ranking Functions)? 排序函数基于一组记录的集合返回一个排序值.一个排序值其实 ...
- Bing Maps进阶系列七:Bing Maps功能导航菜单华丽的变身
Bing Maps进阶系列七:Bing Maps功能导航菜单华丽的变身 Bing Maps Silverlight Control所提供的功能导航是非常强大的,在设计上对扩展的支持非常好,提供了许多用 ...
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
- 【SQL必知必会笔记(2)】检索数据、排序检索数据
上个笔记中介绍了一些关于数据库.SQL的基础知识,并且创建我们后续练习所需的数据库.表以及表之间的关系,从本文开始进入我们的正题:SQL语句的练习. 文章目录 1.检索数据(SELECT语句) 1.1 ...
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- SQL进阶系列之12SQL编程方法
写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...
- SQL进阶系列之10HAVING子句又回来了
写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...
- SQL进阶系列之11让SQL飞起来
写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...
随机推荐
- Allegro---层叠结构设置
PCB层叠结构 层叠结构是一个非常重要的问题,不可忽视,一般选择层叠结构考虑以下原则: ·元件面下面(第二层)为地平面,提供器件屏蔽层以及为顶层布线提供参考平面: ·所有信号层尽可能与地平面相邻: ...
- python3练习100题--024
因为过生日,好几天没做题了,有点松懈. 我要更加加油啦-为了打败现在每天都厌恶的生活! 原题链接:http://www.runoob.com/python/python-exercise-exampl ...
- Vue 任务清单
<style> li{ list-style: none; } #root{ width: 400px; min-height: 400px; box-shadow: 0 0 10px # ...
- 转载一篇棒棒的AWK教程
处理文件经常要用到awk,老是找同事帮忙,次数多了难免被吐槽orz,其实之前也有找过awk的教程,表示一直看不太懂 最近翻到了这篇教程,表示笔者真的太棒了,反正我是看一遍就懂了哈哈 剩下的只是熟悉度的 ...
- input输入框在ios手机上获取焦点后有一个灰色阴影
遇到的场景: 有一个输入框 设置 outline:none 然后我又想给他设置获取焦点的颜色 然后 我给input 设置 border 为 1px t透明的 然后 获取焦点的时候 重新设置border ...
- GoAhead WebServer 架构
https://blog.csdn.net/jungsagacity/article/details/7307012
- Linux - Shell - #!/bin/bash
概述 简单解释一下 shell 脚本卡头的 #!/bin/bash 水一篇, 少一篇 背景 shell 脚本中的注释 通常是 以# 卡头的行 但是有时候执行 shell 的时候, 会有这种内容 #!/ ...
- 牛客竞赛第二场D Kth Minimum Clique 贪心+bitmap
Kth Minimum Clique 题意 给出n(n<100)个点的邻接表,和n个点的权值,求第k大的团(完全子图) 分析 n很小,并且好像没有什么算法和这个有关系,所以可以往暴力枚举的方向想 ...
- 每天进步一点点------Allegro PCB命名规则
PCB命名规则-allegro 一.焊盘命名规则 1. 贴片矩形焊盘 命名规则:SMD+长(L)+宽(W)(mil) 举例:SMD90X60 2. 贴片圆焊盘 命名规则:SMDC+焊盘直径(D) ...
- XSS常见攻击与防御
XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意 ...