我想要每三行生成一个数字
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 |
+--------+-----+
还有其他方法可以实现数学。
期间不会有任何差距答案 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
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
这两个都给出了相同的结果:
但是有一个警告! 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]