如何获取范围内的所有数字
How to get all numbers between a range
我有一个table如下
Id RFrom RTo
.... ....... .....
1 10 14
1 22 25
2 100 102
2 176 180
我想获取每个 Id 的每个 RFrom 和 RTo 之间的所有数字。我的预期结果如下
Id NUMS
.... ......
1 10
1 11
1 12
1 13
1 14
1 22
1 23
1 24
1 25
2 100
2 101
2 102
2 176
2 177
2 178
2 179
2 180
我必须使用游标来实现吗?
这是你的样本table
SELECT * INTO #TEMP FROM
(
SELECT 1 ID, 10 RFROM, 14 RTO
UNION ALL
SELECT 1, 22, 25
UNION ALL
SELECT 2, 100, 102
UNION ALL
SELECT 2, 176, 180
)TAB
您需要对每个Id使用递归来得到结果
;WITH CTE AS
(
SELECT ID,RFROM RFROM1,RTO RTO1
FROM #TEMP
UNION ALL
SELECT T.ID,RFROM1+1,RTO1
FROM #TEMP T
JOIN CTE ON CTE.ID = T.ID
WHERE RFROM1 < RTO1
)
SELECT DISTINCT ID,RFROM1 NUMS
FROM CTE
另一种选择是将 numbers
table 与 join
一起使用——递归可能很耗时。
创建数字 table 有多种选择(我建议创建一个永久的),但这里有一个使用通用-table-表达式创建的临时数字:
with numberstable as (
select top 10000 row_number() over(order by t1.number) as number
from master..spt_values t1
cross join master..spt_values t2
)
select yt.id,
nt.number
from yourtable yt
join numberstable nt on nt.number between yt.rfrom and yt.rto
使用 stacked CTE
创建一个 tally table
,与 recursive CTE
相比,它具有更好的性能
declare @min int
select @min= min(RFrom) from yourtable
;WITH e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2) -- 10*100
SELECT b.id,
a.n
FROM yourtable b
JOIN (SELECT n = Row_number()OVER (ORDER BY n)+ @min-1
FROM e3)a
ON a.n BETWEEN b.RFrom AND b.RTo
ORDER BY n;
检查 here 了解信息
我有一个table如下
Id RFrom RTo
.... ....... .....
1 10 14
1 22 25
2 100 102
2 176 180
我想获取每个 Id 的每个 RFrom 和 RTo 之间的所有数字。我的预期结果如下
Id NUMS
.... ......
1 10
1 11
1 12
1 13
1 14
1 22
1 23
1 24
1 25
2 100
2 101
2 102
2 176
2 177
2 178
2 179
2 180
我必须使用游标来实现吗?
这是你的样本table
SELECT * INTO #TEMP FROM
(
SELECT 1 ID, 10 RFROM, 14 RTO
UNION ALL
SELECT 1, 22, 25
UNION ALL
SELECT 2, 100, 102
UNION ALL
SELECT 2, 176, 180
)TAB
您需要对每个Id使用递归来得到结果
;WITH CTE AS
(
SELECT ID,RFROM RFROM1,RTO RTO1
FROM #TEMP
UNION ALL
SELECT T.ID,RFROM1+1,RTO1
FROM #TEMP T
JOIN CTE ON CTE.ID = T.ID
WHERE RFROM1 < RTO1
)
SELECT DISTINCT ID,RFROM1 NUMS
FROM CTE
另一种选择是将 numbers
table 与 join
一起使用——递归可能很耗时。
创建数字 table 有多种选择(我建议创建一个永久的),但这里有一个使用通用-table-表达式创建的临时数字:
with numberstable as (
select top 10000 row_number() over(order by t1.number) as number
from master..spt_values t1
cross join master..spt_values t2
)
select yt.id,
nt.number
from yourtable yt
join numberstable nt on nt.number between yt.rfrom and yt.rto
使用 stacked CTE
创建一个 tally table
,与 recursive CTE
declare @min int
select @min= min(RFrom) from yourtable
;WITH e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2) -- 10*100
SELECT b.id,
a.n
FROM yourtable b
JOIN (SELECT n = Row_number()OVER (ORDER BY n)+ @min-1
FROM e3)a
ON a.n BETWEEN b.RFrom AND b.RTo
ORDER BY n;
检查 here 了解信息