在SQL中创建范围从n到1

时间:2016-04-06 02:25:47

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


我需要创建一个从1到n的范围编号 例如,参数为@StartingValue

@StartingValue int = 96

然后结果应该是:

Number
-------------
96
95
94
93
92
ff.
1

有没有人知道如何做到这一点?
谢谢。

4 个答案:

答案 0 :(得分:4)

使用Tally Table生成数字:

DECLARE @N INT = 96

;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally(N) AS(
    SELECT TOP(@N) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
    FROM E8
)    
SELECT * FROM CteTally ORDER BY N DESC

Jeff的文章(上面链接)的解释:

  

CTE称为E1(如10E1中的科学记法)仅此而已   只有十个SELECT 1作为单个结果集返回。

     

E2与自己进行E1的CROSS JOIN。这会返回一个结果   一组10 * 10或最多100行。我说"直到"因为如果TOP   功能是100或更少,CTE是"智能"足以知道它   实际上并不需要更进一步,E4和E8甚至不会来   发挥作用。如果TOP的值小于100,则不是全部100行   E2有能力制作。它总能做到   足够根据TOP功能。

     

你可以从那里开始。 E4是E2的CROSS JOIN并将弥补   到100 * 100或10,000行,E8是E4的CROSS JOIN   比大多数人需要更多的行。如果你确实需要更多,那么   只需添加一个E16作为E8的CROSS JOIN并更改最终的FROM子句   来自E16。

     

这个坏孩子的真正惊奇之处在于产生了零   READS 即可。绝对没有,纳达,没有。

答案 1 :(得分:2)

一个简单的方法是数字表。对于合理的数字(最高为数千),您可以使用spt_values

with numbers as (
      select top 96 row_number() over (order by (select null)) as n
      from t
     )
. . . 

另一种方法是递归CTE:

with numbers as (
      select 96 as n
      union all
      select n - 1
      from numbers
      where num > 1
     )

对于较大的值,您需要使用MAXRECURSION选项。

答案 2 :(得分:0)

另一种方式。

SELECT N.number FROM  
  master..spt_values N 
WHERE  
  N.type = 'P' AND 
  N.number BETWEEN 1 AND 96
ORDER BY N.number DESC

有关spt_values What is the purpose of system table master..spt_values and what are the meanings of its values?

的更多详情

答案 3 :(得分:0)

Sequance of no's can be generated by following ways:
1. Using row_number by querying a large table and get the sequance.
2. Using system tables as you can see other people comments.
3. Using recursive CTE.

declare @maxValue int  = 96

; WITH rangetest AS 
(
    SELECT      MinValue =  @maxValue 
    UNION ALL
    SELECT      MinValue = MinValue - 1
    FROM        rangetest
    WHERE       MinValue > 1
) 
SELECT  *
from rangetest
OPTION  (MAXRECURSION 0)