选择两个值之间的所有值

时间:2013-10-17 13:13:38

标签: sql sql-server tsql sql-server-2008-r2

假设我有一个包含以下列的表 (开始,结束,间隔)

有没有什么方法可以获得Start,End之间的所有值以及每一行的间隔? 请注意,(Start,End,Interval)表中的行不止一行,但它们不应重叠。

如果可能,没有循环/游标/临时表/变量表。

示例数据

Start           End        Interval
1               3          1
9               12         1
16              20         2

期望的结果:

Result
1
2
3
9
10
11
12
16
18
20

3 个答案:

答案 0 :(得分:4)

这是递归公用表表达式的一个很好的用例:

;with cte as (
    select [Start] as Result, [End], [Interval]
    from Table1
    union all
    select Result + [Interval], [End], [Interval]
    from cte
    where Result + [Interval] <= [End]
)
select Result
from cte
order by Result

<强> sql fiddle demo

答案 1 :(得分:2)

你可以这样做

WITH tally AS (
  SELECT 0 n
  UNION ALL
  SELECT n + 1 FROM tally WHERE n < 100 -- adjust 100 to a max possible value for (end - start) / interval
)
SELECT start + n * [interval] result
  FROM Table1 t CROSS JOIN tally n
 WHERE n.n <= (t.[end] - t.start) / t.[interval]
 ORDER BY result

注意:如果您执行了大量此类查询,则可以考虑将带有主键的持久数字表tally替换为递归CTE tally n 1}}列。

输出:

| RESULT |
|--------|
|      1 |
|      2 |
|      3 |
|      9 |
|     10 |
|     11 |
|     12 |
|     16 |
|     18 |
|     20 |

这是 SQLFiddle 演示

答案 2 :(得分:1)

我知道你接受了答案,我认为这也是正确的。

<强> Fiddle demo 1

select x.number
from master..spt_values x cross join table1 t
where x.type='p' and x.number between t.[start] and t.[end]
                 and x.number % t.[interval] = 0

结果:

| NUMBER |
|--------|
|      1 |
|      2 |
|      3 |
|      9 |
|     10 |
|     11 |
|     12 |
|     16 |
|     18 |
|     20 |

编辑:如果您想要无限数量,请尝试此方法并根据需要交叉加入更多数字表。这个例子最高可达9999。

<强> Fiddle demo 2

;WITH Digits AS (
    select Digit 
    from ( values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) 
          AS t(Digit))
,Numbers AS (
    select u.Digit + t.Digit*10 + h.Digit*100 + th.Digit*1000 as number
    from Digits u
    cross join Digits t
    cross join Digits h
    cross join Digits th
    --Add more cross joins as required
    )

Select number
From Numbers x cross join table1 t
where x.number between t.[start] and t.[end]
      and x.number % t.[interval] = 0;
Order by number