SQL 生成序号的四种方式
- 格式:docx
- 大小:114.07 KB
- 文档页数:7
sql四个排名函数生成记录序号排名函数是SQL Server2005新加的功能。
在SQL Server2005中有如下四个排名函数:1. row_number顺序生成序号2. rank 相同的序值序号相同,但序号会跳号3. dense_rank相同的序值序号相同,序号顺充递增4. ntile 装桶,把记录分成指的桶数,编序号下面分别介绍一下这四个排名函数的功能及用法。
在介绍之前假设有一个t_table表,表结构与表中的数据如图1所示:图1其中field1字段的类型是int,field2字段的类型是varchar一、row_numberrow_number函数的用途是非常广泛,这个函数的功能是为查询出来的每一行记录生成一个序号。
row_number函数的用法如下面的SQL语句所示:select row_number() over(order by field1) as row_number,* from t_tabl e上面的SQL语句的查询结果如图2所示。
图2其中row_number列是由row_number函数生成的序号列。
在使用row_number 函数是要使用over子句选择对某一列进行排序,然后才能生成序号。
实际上,row_number函数生成序号的基本原理是先使用over子句中的排序语句对记录进行排序,然后按着这个顺序生成序号。
over子句中的order by子句与SQL语句中的order by子句没有任何关系,这两处的order by 可以完全不同,如下面的SQL语句所示:select row_number() over(order by field2 desc) as row_number,* from t _table order by field1 desc上面的SQL语句的查询结果如图3所示。
图3我们可以使用row_number函数来实现查询表中指定范围的记录,一般将其应用到Web应用程序的分页功能上。
Sql四⼤排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介排名函数是Sql Server2005新增的功能,下⾯简单介绍⼀下他们各⾃的⽤法和区别。
我们新建⼀张Order表并添加⼀些初始数据⽅便我们查看效果。
CREATE TABLE [dbo].[Order]([ID] [int] IDENTITY(1,1) NOT NULL,[UserId] [int] NOT NULL,[TotalPrice] [int] NOT NULL,[SubTime] [datetime] NOT NULL,CONSTRAINT [PK_Order] PRIMARY KEY CLUSTERED([ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]GOSET IDENTITY_INSERT [dbo].[Order] ONGOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (1, 1, 100, CAST(0x0000A419011D32AF AS DateTime))GOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (2, 2, 500, CAST(0x0000A419011D40BA AS DateTime))GOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (3, 3, 300, CAST(0x0000A419011D4641 AS DateTime))GOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (4, 2, 1000, CAST(0x0000A419011D4B72 AS DateTime))GOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (5, 1, 520, CAST(0x0000A419011D50F3 AS DateTime))GOINSERT [dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (6, 2, 2000, CAST(0x0000A419011E50C9 AS DateTime))GOSET IDENTITY_INSERT [dbo].[Order] OFFGOALTER TABLE [dbo].[Order] ADD CONSTRAINT [DF_Order_SubTime] DEFAULT (getdate()) FOR [SubTime]GO 附上表结构和初始数据图:⼀、ROW_NUMBER row_number的⽤途的⾮常⼴泛,排序最好⽤他,⼀般可以⽤来实现web程序的分页,他会为查询出来的每⼀⾏记录⽣成⼀个序号,依次排序且不会重复,注意使⽤row_number函数时必须要⽤over⼦句选择对某⼀列进⾏排序才能⽣成序号。
SQLServer序列(SEQUENCE)使⽤众所周知,在之前的SQL SERVER版本中,⼀般采⽤GUID或者IDENTITY来作为标⽰符,但是IDENTITY是⼀个表对象,只能保证在⼀张表⾥⾯的序列,当我们遇到以下情况时,如上表,我们需要在多表之间,实现ID的⼀致性,在SQL SERVER⾥⾯就会有⼀定的⿇烦,通常我们会使⽤额外使⽤⼀张TEMP表来映射这些ID的关系然后再从中取序列来完成。
SEQUENCE在ORACLE中其实很早就存在了,SQL SERVER 2012的SEQUENCE功能和那个相似,是⼀个基于SCHEMA的对象,所以可以被多表调⽤。
序列是⽤户定义的绑定到架构的对象,该对象可根据创建序列所依据的规范来⽣成数值序列。
这组数值以定义的间隔按升序或降序⽣成,并且可配置为⽤尽时重新启动(循环)。
序列不与特定表相关联,这⼀点与标识列不同。
应⽤程序将引⽤某⼀序列对象以便检索其下⼀个值。
序列与表之间的关系由应⽤程序控制。
⽤户应⽤程序可以引⽤⼀个序列对象,并跨多个⾏和表协调值。
与在插⼊⾏时⽣成的标识列值不同,应⽤程序可以获得下⼀个序列号,⽽不必通过调⽤ NEXT VALUE FOR 函数来插⼊⾏。
使⽤sp_sequence_get_range同时获取多个序列号。
SEQUENCE语法如下:(创建⼀个序列对象并指定其属性)CREATE SEQUENCE [schema_name . ] sequence_name[ AS [ built_in_integer_type | user-defined_integer_type ] ][ START WITH <constant> ][ INCREMENT BY <constant> ][ { MINVALUE [ <constant> ] } | { NO MINVALUE } ][ { MAXVALUE [ <constant> ] } | { NO MAXVALUE } ][ CYCLE | { NO CYCLE } ][ { CACHE [ <constant> ] } | { NO CACHE } ][ ; ]sequence_name 指定数据库中标识序列的唯⼀名称。
利用"SQL"语句自动生成序号的两种方式SQL Server2005数据库中利用SQL语句自动生成序号:1.首先,我们来介绍第一种方式:◆查询的SQL语句如下:◆运行的结果:2.最后,我们来介绍第二种方式:在我们利用这种方式生成自动序号时,Test_Table必须在数据库中不能存在,因为在执行这些SQL语句的时后自动会创建表。
以下为实现SQL server中按年月日生成日期型自增编码的sql脚本:/** 测试表*/CREATE TABLE [dbo].[CustomIDTest] ([ID] [int] NOT NULL ,[Code] [char] (8) NOT NULL)/**//** 功能:按 YYYYxxxx 格式生成目标年份的最大编码,数据类型为 CHAR(8)* 说明:特定表范围内有效* 未处理溢出情况(当表中某年值已达到YYYY9999)*/CREATE FUNCTION dbo.GenCustomCode(@Year INT)RETURNS CHAR(8)ASBEGINDECLARE@Code CHAR(8),@MinCodeInYear CHAR(8),@MaxCodeInYear CHAR(8)SELECT @MinCodeInYear = CONVERT(CHAR(4), @Year) + '0001', @MaxCodeInYear = CONVERT(CHAR(4), @Year) + '9999'SELECT @Code = MAX(Code) FROM CustomIDTest WHERE Code >= @MinCodeInYear AND Code <= @MaxCodeInYearIF @Code IS NOT NULL AND @Year = CONVERT(INT, SUBSTRING(@Code, 1, 4)) /**//*IF @Code = @MaxCodeInYear 溢出处理*/SET @Code = CONVERT(INT, @Code) + 1ELSESET @Code = @MinCodeInYearRETURN @CodeEND/**//** 功能:按 YYYYxxxx 格式生成目标年份的最大ID,数据类型为 INT* 说明:特定表范围内有效* 未处理溢出情况(当表中某年值已达到YYYY9999)*/CREATE FUNCTION dbo.GenCustomID(@Year INT)RETURNS INTASBEGINDECLARE@ID INT,@MinIDInYear INT,@MaxIDInYear INTSELECT @MinIDInYear = @Year*10000 + 1, @MaxIDInYear = @Year*10000 + 9999SELECT @ID = MAX(ID) FROM CustomIDTest WHERE ID >= @MinIDInYear AND ID <= @MaxIDInYearIF @ID IS NOT NULL AND @Year = @ID/10000/**//*IF @ID = @MaxIDInYear 溢出处理*/SET @ID = @ID + 1ELSESET @ID = @MinIDInYearRETURN @IDEND-- 测试-- 自定义年份内自增INSERT INTO CustomIDTest([ID], [Code])SELECT dbo.GenCustomID(DatePart(YY, DATEADD(YY, -1, GetDate()))), dbo.GenCustomCode(DatePart(YY, DATEADD(YY, -1, GetDate())))UNIONSELECT dbo.GenCustomID(DatePart(YY, GetDate())), dbo.GenCustomCode(DatePart(YY, GetDate()))UNIONSELECT dbo.GenCustomID(DatePart(YY, DATEADD(YY, 1, GetDate()))), dbo.GenCustomCode(DatePart(YY, DATEADD(YY, 1, GetDate())))SELECT * FROM CustomIDTest结果ID Code----------- --------20060001 2006000120060002 2006000220060003 2006000320060004 2006000420070001 2007000120070002 2007000220070003 2007000320070004 2007000420080001 2008000120080002 2008000220080003 2008000320080004 20080004说明:1、对于此示例,一年内最大增量只有,9999,需要考虑溢出如何处理,此版本未处理2、因此,根据实际需求,我们可以选择以“天”为编码前缀,并且扩大自增部分长度,避免溢出,3、当然此时得考虑,使用 INT 型长度是否足够4、此版本自定义函数,使用传入年份参数5、若欲始终使用当前系统日期,而不显示指定年份,则需要建立一视图来获取当前日期(因SQLServer中标量函数,不能使用 GetDate() 这样的非标量函数)详细讲解有关获取当月天数的实用技巧获取当月天数的实用技巧:以下是引用片段:分析如下:以下是引用片段:以下是引用片段:5. SYBASESELECT TOP N * FROM TABLE16. mysql:select * from table_name limit N为什么SQL不许在视图定义ORDER BY子句发布时间:2007.08.03 05:01来源:赛迪网作者:luoyingshu 问:为什么SQL Server不允许在视图定义使用ORDER BY子句?答: SQL Server之所以不允许在视图定义中使用ORDER BY子句是为了遵守ANSI SQL-92标准。
sql中随机生成八位数字母的函数在SQL中,我们经常需要生成随机的数据,其中包括随机生成八位数字母的需求。
本文将介绍如何在SQL中编写一个函数来实现这个功能。
首先,我们需要了解SQL中的随机函数。
在大多数数据库管理系统中,都提供了随机函数来生成随机数。
例如,在MySQL中,可以使用RAND()函数来生成一个0到1之间的随机数。
在Oracle中,可以使用DBMS_RANDOM.VALUE函数来生成一个0到1之间的随机数。
接下来,我们需要了解如何生成随机的字母。
在ASCII码表中,字母的ASCII码范围是65到90(大写字母)和97到122(小写字母)。
因此,我们可以使用ASCII码来生成随机的字母。
现在,我们可以开始编写函数了。
以下是一个在MySQL中实现的函数示例:```sqlDELIMITER //CREATE FUNCTION generate_random_letters()RETURNS VARCHAR(8)BEGINDECLARE letters VARCHAR(8) DEFAULT '';DECLARE i INT DEFAULT 1;DECLARE ascii_code INT;WHILE i <= 8 DOSET ascii_code = FLOOR(RAND() * 52) + 65;IF ascii_code > 90 THENSET ascii_code = ascii_code + 6;END IF;SET letters = CONCAT(letters, CHAR(ascii_code));SET i = i + 1;END WHILE;RETURN letters;END //DELIMITER ;```在这个函数中,我们首先定义了一个变量`letters`,用于保存生成的随机字母。
然后,我们使用一个循环来生成八位随机字母。
在每次循环中,我们使用`RAND()`函数生成一个0到1之间的随机数,并将其乘以52,然后加上65,得到一个65到116之间的随机数。
sql结果增加序号的方法SQL是一种用于管理和操作数据库的编程语言。
在处理数据库中的查询结果时,有时需要为每一行结果添加序号。
以下是几种常见的方法来实现在SQL结果中增加序号的方法。
1. 使用ROW_NUMBER()函数:ROW_NUMBER()函数是一个用于给查询结果中的每一行分配唯一递增序号的窗口函数。
以下是一个示例代码,演示如何使用ROW_NUMBER()函数添加序号列。
```SELECT ROW_NUMBER() OVER (ORDER BY column_name) AS RowNumber, column1, column2, ...FROM table_name```在上述代码中,column_name是用于排序的列名,table_name是要查询的表名。
通过将ROW_NUMBER()函数与OVER子句结合使用,可以为每一行结果创建一个名为RowNumber的序号列。
2. 使用IDENTITY列:IDENTITY列是一种特殊的列类型,用于自动为表中的每一行分配唯一的递增值。
以下是一个示例代码,演示如何在创建表时添加IDENTITY列。
```CREATE TABLE table_name(Id int IDENTITY(1,1),column1 data_type,column2 data_type,...)```在上述代码中,Id列将作为IDENTITY列,并通过指定初始值为1和增量为1来自动为表中的每一行设置唯一的递增值。
3. 使用变量和UPDATE语句:如果您已经查询了一个没有序号的结果集,并且希望在后续操作中添加序号,可以使用变量和UPDATE语句来实现。
以下是一个示例代码,演示如何在现有表中添加序号列。
```DECLARE @RowNumber int = 1UPDATE table_nameSET column_name = @RowNumber, @RowNumber = @RowNumber + 1```在上述代码中,table_name是要更新的表名,column_name是要添加序号的列名。
sql⾃增号1: ⾃增列类型为:int identity(1,1) 当然也可以是bigint,smallinteg: create table tbName(id int identity(1,1),description varchar(20))或在⽤企业管理器设计表字段时,将字段设为int,将标识设为是,其它⽤默认即可2: 查询时加序号:a:没有主键的情形:Select identity(int,1,1) as iid,* into #tmp from TableNameSelect * from #tmpDrop table #tmpb:有主键的情形:Select (Select sum(1) from TableName where KeyField <= a.KeyField) as iid,* from TableName a3:⽣成⾃增序列号的表eg: ⽣成⼀列0-30的数Select top 30 (select sum(1) from sysobjects where name<= )-1 as id from sysobjects a 当然,可能sysobjects 中没有这么多条记录,⽐如只有100条,我需⽣成1-800的序列号如下处理:Select (Select sum(1) from (Select top 800 as name1, as name2 from sysobjects a ,sysobjects b) cc where name1<= 1 and name2 <= 2 ) from(Select top 800 as name1, as name2 from sysobjects a ,sysobjects b) dd应⽤举例eg1:create table t(⽇期 char(8),请假⼈数 int)insert t select '20031001',3Union all select '20031003',2Union all select '20031004',1Union all select '30031031',5要列出2003年10⽉每⼀天的请假⼈数,若没有,以0表⽰。
SQLServer排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)排名函数是Sql Server2005新增的功能,下⾯简单介绍⼀下他们各⾃的⽤法和区别。
我们新建⼀张Order表并添加⼀些初始数据⽅便我们查看效果。
CREATE TABLE[dbo].[Order]([ID][int]IDENTITY(1,1) NOT NULL,[UserId][int]NOT NULL,[TotalPrice][int]NOT NULL,[SubTime][datetime]NOT NULL,CONSTRAINT[PK_Order]PRIMARY KEY CLUSTERED([ID]ASC)WITH (PAD_INDEX =OFF, STATISTICS_NORECOMPUTE =OFF, IGNORE_DUP_KEY =OFF, ALLOW_ROW_LOCKS =ON, ALLOW_PAGE_LOCKS =ON) ON[PRIMARY]) ON[PRIMARY]GOSET IDENTITY_INSERT[dbo].[Order]ONGOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (1, 1, 100, CAST(0x0000A419011D32AF AS DateTime))GOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (2, 2, 500, CAST(0x0000A419011D40BA AS DateTime))GOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (3, 3, 300, CAST(0x0000A419011D4641AS DateTime))GOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (4, 2, 1000, CAST(0x0000A419011D4B72AS DateTime))GOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (5, 1, 520, CAST(0x0000A419011D50F3AS DateTime))GOINSERT[dbo].[Order] ([ID], [UserId], [TotalPrice], [SubTime]) VALUES (6, 2, 2000, CAST(0x0000A419011E50C9AS DateTime))GOSET IDENTITY_INSERT[dbo].[Order]OFFGOALTER TABLE[dbo].[Order]ADD CONSTRAINT[DF_Order_SubTime]DEFAULT (getdate()) FOR[SubTime]GO 附上表结构和初始数据图:⼀、ROW_NUMBER row_number的⽤途的⾮常⼴泛,排序最好⽤他,⼀般可以⽤来实现web程序的分页,他会为查询出来的每⼀⾏记录⽣成⼀个序号,依次排序且不会重复,注意使⽤row_number函数时必须要⽤over⼦句选择对某⼀列进⾏排序才能⽣成序号。
sql 按字段生成序号的方法以SQL按字段生成序号的方法为标题在SQL查询中,有时候我们需要为查询结果中的每一行生成一个序号。
这个序号可以用于标识每一行的顺序,方便后续的数据处理和分析。
本文将介绍一些常用的方法,用于在SQL查询中按字段生成序号。
一、使用ROW_NUMBER()函数ROW_NUMBER()函数是SQL中常用的用于生成序号的函数之一。
它可以为查询结果集中的每一行生成一个唯一的序号,序号的值从1开始递增。
下面是一个使用ROW_NUMBER()函数生成序号的示例:```sqlSELECT ROW_NUMBER() OVER(ORDER BY column_name) AS row_number, column1, column2FROM table_name;```在上面的示例中,ROW_NUMBER()函数被用于SELECT语句的列列表中,用于生成一个名为row_number的序号列。
在OVER子句中,我们可以指定一个ORDER BY子句,用于指定生成序号的顺序。
在这个示例中,我们按照column_name字段的值进行排序。
二、使用RANK()函数RANK()函数也是用于生成序号的函数之一。
它可以为查询结果集中的每一行生成一个序号,序号的值可以相同,表示并列的排名。
下面是一个使用RANK()函数生成序号的示例:```sqlSELECT RANK() OVER(ORDER BY column_name) AS rank_number, column1, column2FROM table_name;```在上面的示例中,RANK()函数被用于SELECT语句的列列表中,用于生成一个名为rank_number的序号列。
在OVER子句中,我们同样可以指定一个ORDER BY子句,用于指定生成序号的顺序。
三、使用DENSE_RANK()函数DENSE_RANK()函数也可以用于生成序号,与RANK()函数类似,但是它不会跳过相同值的序号,即使有相同的值,序号也会连续递增。
mysql中的sql语句完整执⾏流程SQL Select 语句完整的执⾏顺序:1、from ⼦句组装来⾃不同数据源的数据;2、where ⼦句基于指定的条件对记录⾏进⾏筛选;3、group by ⼦句将数据划分为多个分组;4、使⽤聚集函数进⾏计算;5、使⽤ having ⼦句筛选分组;6、计算所有的表达式;7、select 的字段;8、使⽤ order by 对结果集进⾏排序。
SQL 语⾔不同于其他编程语⾔的最明显特征是处理代码的顺序。
在⼤多数据库语⾔中,代码按编码顺序被处理。
但在 SQL 语句中,第⼀个被处理的⼦句式 FROM,⽽不是第⼀出现的 SELECT。
SQL 查询处理的步骤序号:(1) FROM <left_table>(2) <join_type> JOIN <right_table>(3) ON <join_condition>(4) WHERE <where_condition>(5) GROUP BY <group_by_list>(6) WITH {CUBE | ROLLUP}(7) HAVING <having_condition>(8) SELECT(9) DISTINCT(9) ORDER BY <order_by_list>(10) <TOP_specification> <select_list>以上每个步骤都会产⽣⼀个虚拟表,该虚拟表被⽤作下⼀个步骤的输⼊。
这些虚拟表对调⽤者(客户端应⽤程序或者外部查询)不可⽤。
只有最后⼀步⽣成的表才会会给调⽤者。
如果没有在查询中指定某⼀个⼦句,将跳过相应的步骤。
逻辑查询处理阶段简介:1、 FROM:对 FROM ⼦句中的前两个表执⾏笛卡尔积(交叉联接),⽣成虚拟表 VT1。
2、 ON:对 VT1 应⽤ ON 筛选器,只有那些使为真才被插⼊到 TV2。
sql四个排名函数生成记录序号
排名函数是SQL Server2005新加的功能。
在SQL Server2005中有如下四个排名函数:
1. row_number顺序生成序号
2. rank 相同的序值序号相同,但序号会跳号
3. dense_rank相同的序值序号相同,序号顺充递增
4. ntile 装桶,把记录分成指的桶数,编序号
下面分别介绍一下这四个排名函数的功能及用法。
在介绍之前假设有一个t_table表,表结构与表中的数据如图1所示:
图1
其中field1字段的类型是int,field2字段的类型是varchar
一、row_number
row_number函数的用途是非常广泛,这个函数的功能是为查询出来的每一行记录生成一个序号。
row_number函数的用法如下面的SQL语句所示:
select row_number() over(order by field1) as row_number,* from t_tabl e
上面的SQL语句的查询结果如图2所示。
图2
其中row_number列是由row_number函数生成的序号列。
在使用row_number 函数是要使用over子句选择对某一列进行排序,然后才能生成序号。
实际上,row_number函数生成序号的基本原理是先使用over子句中的排序语句对记录进行排序,然后按着这个顺序生成序号。
over子句中的order by子句与SQL语句中的order by子句没有任何关系,这两处的order by 可以完全不同,如下面的SQL语句所示:
select row_number() over(order by field2 desc) as row_number,* from t _table order by field1 desc
上面的SQL语句的查询结果如图3所示。
图3
我们可以使用row_number函数来实现查询表中指定范围的记录,一般将其应用到Web应用程序的分页功能上。
下面的SQL语句可以查询t_table表中第2条和第3条记录:
with t_rowtable
as
(
select row_number() over(order by field1) as row_number,* from t_ table
)
select * from t_rowtable where row_number>1 and row_number < 4 order by field1
上面的SQL语句的查询结果如图4所示。
图4
上面的SQL语句使用了CTE,关于CTE的介绍将读者参阅《SQL Server2005杂谈(1):使用公用表表达式(CTE)简化嵌套SQL》。
另外要注意的是,如果将row_number函数用于分页处理,over子句中的order by 与排序记录的order by 应相同,否则生成的序号可能不是有续的。
当然,不使用row_number函数也可以实现查询指定范围的记录,就是比较麻烦。
一般的方法是使用颠倒Top来实现,例如,查询t_table表中第2条和第3条记录,可以先查出前3条记录,然后将查询出来的这三条记录按倒序排序,再取前2条记录,最后再将查出来的这2条记录再按倒序排序,就是最终结果。
SQL语句如下:
select * from (select top 2 * from( select top 3 * from t_table order by field1) a order by field1 desc) b order by field1
上面的SQL语句查询出来的结果如图5所示。
图5
这个查询结果除了没有序号列row_number,其他的与图4所示的查询结果完全一样。
二、rank
rank函数考虑到了over子句中排序字段值相同的情况,为了更容易说明问题,在t_table表中再加一条记录,如图6所示。
图6
在图6所示的记录中后三条记录的field1字段值是相同的。
如果使用rank 函数来生成序号,这3条记录的序号是相同的,而第4条记录会根据当前的记录数生成序号,后面的记录依此类推,也就是说,在这个例子中,第4条记录的序号是4,而不是2。
rank函数的使用方法与row_number函数完全相同,SQL语句如下:
select rank() over(order by field1),* from t_table order by field1
上面的SQL语句的查询结果如图7所示。
图7
三、dense_rank
dense_rank函数的功能与rank函数类似,只是在生成序号时是连续的,而rank函数生成的序号有可能不连续。
如上面的例子中如果使用dense_rank函数,第4条记录的序号应该是2,而不是4。
如下面的SQL语句所示:
select dense_rank() over(order by field1),* from t_table order by fie ld1
上面的SQL语句的查询结果如图8所示。
图8
读者可以比较图7和图8所示的查询结果有什么不同
四、ntile
ntile函数可以对序号进行分组处理。
这就相当于将查询出来的记录集放到指定长度的数组中,每一个数组元素存放一定数量的记录。
ntile函数为每条记录生成的序号就是这条记录所有的数组元素的索引(从1开始)。
也可以将每一个分配记录的数组元素称为“桶”。
ntile函数有一个参数,用来指定桶数。
下面的SQL语句使用ntile函数对t_table表进行了装桶处理:
select ntile(4) over(order by field1) as bucket,* from t_table 上面的SQL语句的查询结果如图9所示。
图9
由于t_table表的记录总数是6,而上面的SQL语句中的ntile函数指定了桶数为4。
也许有的读者会问这么一个问题,SQL Server2005怎么来决定某一桶应该放多少记录呢?可能t_table表中的记录数有些少,那么我们假设t_table表中有59条记录,而桶数是5,那么每一桶应放多少记录呢?
实际上通过两个约定就可以产生一个算法来决定哪一个桶应放多少记录,这两个约定如下:
1. 编号小的桶放的记录不能小于编号大的桶。
也就是说,第1捅中的记录数只能大于等于第2桶及以后的各桶中的记录。
2. 所有桶中的记录要么都相同,要么从某一个记录较少的桶开始后面所有捅的记录数都与该桶的记录数相同。
也就是说,如果有个桶,前三桶的记录数都是10,而第4捅的记录数是6,那么第5桶和第6桶的记录数也必须是6。
根据上面的两个约定,可以得出如下的算法:
// mod表示取余,div表示取整
if(记录总数 mod 桶数 == 0)
{
recordCount = 记录总数 div 桶数;
将每桶的记录数都设为recordCount
}
else
{
recordCount1 = 记录总数 div 桶数 + 1;
int n = 1; // n表示桶中记录数为recordCount1的最大桶数
m = recordCount1 * n;
while(((记录总数 - m) mod (桶数 - n)) != 0 )
{
n++;
m = recordCount1 * n;
}
recordCount2 = (记录总数 - m) div (桶数 - n);
将前n个桶的记录数设为recordCount1
将n + 1个至后面所有桶的记录数设为recordCount2
}
根据上面的算法,如果记录总数为59,桶数为5,则前4个桶的记录数都是12,最后一个桶的记录数是11。
如果记录总数为53,桶数为5,则前3个桶的记录数为11,后2个桶的记录数为10。
就拿本例来说,记录总数为6,桶数为4,则会算出recordCount1的值为2,在结束while循环后,会算出recordCount2的值是1,因此,前2个桶的记录是2,后2个桶的记录是1。