How to generate a range of numbers between two numbers?

后端 未结 30 1873
执念已碎
执念已碎 2020-11-22 10:16

I have two numbers as input from the user, like for example 1000 and 1050.

How do I generate the numbers between these two numbers, using

相关标签:
30条回答
  • 2020-11-22 10:23

    This will also do

    DECLARE @startNum INT = 1000;
    DECLARE @endNum INT = 1050;
    INSERT  INTO dbo.Numbers
            ( Num
            )
            SELECT  CASE WHEN MAX(Num) IS NULL  THEN @startNum
                         ELSE MAX(Num) + 1
                    END AS Num
            FROM    dbo.Numbers
    GO 51
    
    0 讨论(0)
  • 2020-11-22 10:24

    Here's what I came up with:

    create or alter function dbo.fn_range(@start int, @end int)  returns table
    return
    with u2(n) as (
        select n 
        from (VALUES (0),(1),(2),(3)) v(n)
    ), 
    u8(n) as (
        select
            x0.n | x1.n * 4 | x2.n * 16 | x3.n * 64 as n
        from u2 x0, u2 x1, u2 x2, u2 x3
    )
    select 
        @start + s.n as n
    from (
        select
            x0.n | isnull(x1.n, 0) * 256 | isnull(x2.n, 0) * 65536 as n
        from u8 x0 
        left join u8 x1 on @end-@start > 256
        left join u8 x2 on @end-@start > 65536
    ) s
    where s.n < @end - @start
    

    Generates up to 2^24 values. Join conditions keep it fast for small values.

    0 讨论(0)
  • 2020-11-22 10:25

    slartidan's answer can be improved, performance wise, by eliminating all references to the cartesian product and using ROW_NUMBER() instead (execution plan compared):

    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM 
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x1(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x2(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x3(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x4(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x5(x)
    ORDER BY n
    

    Wrap it inside a CTE and add a where clause to select desired numbers:

    DECLARE @n1 AS INT = 100;
    DECLARE @n2 AS INT = 40099;
    WITH numbers AS (
        SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM 
        (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x1(x),
        (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x2(x),
        (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x3(x),
        (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x4(x),
        (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x5(x)
    )
    SELECT numbers.n
    FROM numbers
    WHERE n BETWEEN @n1 and @n2
    ORDER BY n
    
    0 讨论(0)
  • 2020-11-22 10:26
    SELECT DISTINCT n = number 
    FROM master..[spt_values] 
    WHERE number BETWEEN @start AND @end
    

    Demo

    Note that this table has a maximum of 2048 because then the numbers have gaps.

    Here's a slightly better approach using a system view(since from SQL-Server 2005):

    ;WITH Nums AS
    (
      SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id]) 
      FROM sys.all_objects 
    
    )
    SELECT n FROM Nums 
    WHERE n BETWEEN @start AND @end
    ORDER BY n;
    

    Demo

    or use a custom a number-table. Credits to Aaron Bertrand, i suggest to read the whole article: Generate a set or sequence without loops

    0 讨论(0)
  • 2020-11-22 10:27

    an alternative solution is recursive CTE:

    DECLARE @startnum INT=1000
    DECLARE @endnum INT=1050
    ;
    WITH gen AS (
        SELECT @startnum AS num
        UNION ALL
        SELECT num+1 FROM gen WHERE num+1<=@endnum
    )
    SELECT * FROM gen
    option (maxrecursion 10000)
    
    0 讨论(0)
  • 2020-11-22 10:27

    It work for me !

    select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount
    from sys.all_objects a
    
    0 讨论(0)
提交回复
热议问题