每3行生成行号

时间:2017-02-09 13:09:42

标签: sql sql-server tsql sql-server-2012

我想要每三行生成一个数字

CREATE TABLE #test(period INT)

INSERT INTO #test
VALUES      (602),(603),(604),(605),(606),(607),(608),(609)

我知道我们可以使用row_number窗函数或while循环或cursor

生成序列
SELECT period,
       ( Row_number()OVER(ORDER BY period) - 1 ) / 3 + 1
FROM   #test 

结果;

+--------+-----+
| period | seq |
+--------+-----+
|    602 |   1 |
|    603 |   1 |
|    604 |   1 |
|    605 |   2 |
|    606 |   2 |
|    607 |   2 |
|    608 |   3 |
|    609 |   3 |
+--------+-----+

还有其他方法可以实现数学

期间不会有任何差距

3 个答案:

答案 0 :(得分:6)

数学或算术方法可以是使用周期数字本身:

-- table init here
DECLARE @MIN_PERIOD INT = (SELECT MIN(period) FROM #test)

SELECT period,
       (period - @MIN_PERIOD) / 3 + 1 AS seq
FROM   #test 

只要“期间之间没有任何差距”仍然存在,这就有效。

如果您在主查询中需要WHERE子句,请将其应用于SELECT MIN()查询。只要WHERE不会导致时间间隔,就可以正常工作。

答案 1 :(得分:3)

使用NTILE()函数可以实现这一点,但我认为它不比ROW_NUMBER()更有效,主要是因为这种方法必须得到总计数才能确定基团。

创建测试环境:

/*  -- SQL 2016
DROP TABLE IF EXISTS #test;
GO
*/

IF OBJECT_ID('tempdb.dbo.#test') IS NOT NULL DROP TABLE #test

CREATE TABLE #test(period INT);
GO

INSERT INTO #test -- Make it bigger
VALUES      (602),(603),(604),(605),(606),(607),(608),(609);
GO 51

ROW_NUMBER方法:

SELECT /*ROW_NUM*/ period,
       ( Row_number()OVER(ORDER BY period) - 1 ) / 3 + 1
FROM   #test;
GO

ROW_NUMBER

IO和时间表现: 缩短了可读性

  

(400行受影响)表'工作台'。扫描计数0,逻辑读取   0,物理读取0   '#test_00000000000E'。扫描计数1,逻辑读取1,物理读取0

     

(1行受影响)

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 85   毫秒。

NTILE方法

DECLARE @ntile_var int;

SELECT @ntile_var = COUNT(*) FROM #test;

SELECT /*NTILE*/period
    , NTILE(@ntile_var / 3) OVER (ORDER BY period)
FROM #test

IO和时间表现: 缩短了可读性

  

SQL Server解析和编译时间:CPU时间= 0 ms,经过时间=   0毫秒。

     

SQL Server执行时间:CPU时间= 0 ms,已用时间= 0 ms。

     

SQL Server解析和编译时间:CPU时间= 0 ms,经过时间=   0毫秒

     

表   '#test__00000000000E'。扫描计数1,逻辑读取1,物理读取0

     

(1行受影响)

     

SQL Server执行时间:CPU时间= 0 ms,已用时间= 0 ms。

     

(400行受影响)表'工作台'。扫描计数3,逻辑读取   811,物理读取0    表   '#TEST ___ 00000000000E'。扫描计数1,逻辑读取1,物理读取0

     

(1行受影响)

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 93

NTILE

这两个都给出了相同的结果:

Results_GroupsOf3

但是有一个警告! MSDN充分说明(强调添加)

  

如果分区中的行数不能被整除   integer_expression,这将导致两个大小不同的组   一名成员。较大的组在订单中的较小组之前   由OVER子句指定。例如,如果总行数   是53,组的数量是5,前三组将   有11行,其余两组每行10行。

因此,使用NTILE方法,您可以获得一些4个组,因此其余组可以是3个。

答案 2 :(得分:1)

这样的事情......

WITH X AS (
SELECT *
     ,ROW_NUMBER() OVER (ORDER BY [period] ASC) rn 
FROM #test
 )
 SELECT [period]
      ,ROW_NUMBER() OVER (PARTITION BY (X.rn % 3) ORDER BY rn ASC) rn 
FROM X
ORDER BY [period]