How to generate a range of numbers between two numbers?

后端 未结 30 1874
执念已碎
执念已碎 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:38

    Nothing new but I rewrote Brian Pressler solution to be easier on the eye, it might be useful to someone (even if it's just future me):

    alter function [dbo].[fn_GenerateNumbers]
    (   
        @start int,
        @end  int
    ) returns table
    return
    
    with 
    b0 as (select n from (values (0),(0x00000001),(0x00000002),(0x00000003),(0x00000004),(0x00000005),(0x00000006),(0x00000007),(0x00000008),(0x00000009),(0x0000000A),(0x0000000B),(0x0000000C),(0x0000000D),(0x0000000E),(0x0000000F)) as b0(n)),
    b1 as (select n from (values (0),(0x00000010),(0x00000020),(0x00000030),(0x00000040),(0x00000050),(0x00000060),(0x00000070),(0x00000080),(0x00000090),(0x000000A0),(0x000000B0),(0x000000C0),(0x000000D0),(0x000000E0),(0x000000F0)) as b1(n)),
    b2 as (select n from (values (0),(0x00000100),(0x00000200),(0x00000300),(0x00000400),(0x00000500),(0x00000600),(0x00000700),(0x00000800),(0x00000900),(0x00000A00),(0x00000B00),(0x00000C00),(0x00000D00),(0x00000E00),(0x00000F00)) as b2(n)),
    b3 as (select n from (values (0),(0x00001000),(0x00002000),(0x00003000),(0x00004000),(0x00005000),(0x00006000),(0x00007000),(0x00008000),(0x00009000),(0x0000A000),(0x0000B000),(0x0000C000),(0x0000D000),(0x0000E000),(0x0000F000)) as b3(n)),
    b4 as (select n from (values (0),(0x00010000),(0x00020000),(0x00030000),(0x00040000),(0x00050000),(0x00060000),(0x00070000),(0x00080000),(0x00090000),(0x000A0000),(0x000B0000),(0x000C0000),(0x000D0000),(0x000E0000),(0x000F0000)) as b4(n)),
    b5 as (select n from (values (0),(0x00100000),(0x00200000),(0x00300000),(0x00400000),(0x00500000),(0x00600000),(0x00700000),(0x00800000),(0x00900000),(0x00A00000),(0x00B00000),(0x00C00000),(0x00D00000),(0x00E00000),(0x00F00000)) as b5(n)),
    b6 as (select n from (values (0),(0x01000000),(0x02000000),(0x03000000),(0x04000000),(0x05000000),(0x06000000),(0x07000000),(0x08000000),(0x09000000),(0x0A000000),(0x0B000000),(0x0C000000),(0x0D000000),(0x0E000000),(0x0F000000)) as b6(n)),
    b7 as (select n from (values (0),(0x10000000),(0x20000000),(0x30000000),(0x40000000),(0x50000000),(0x60000000),(0x70000000)) as b7(n))
    
    select s.n
    from (
        select
              b7.n
            | b6.n
            | b5.n
            | b4.n
            | b3.n
            | b2.n
            | b1.n
            | b0.n
            + @start
             n
        from b0
        join b1 on b0.n <= @end-@start and b1.n <= @end-@start
        join b2 on b2.n <= @end-@start
        join b3 on b3.n <= @end-@start
        join b4 on b4.n <= @end-@start
        join b5 on b5.n <= @end-@start
        join b6 on b6.n <= @end-@start
        join b7 on b7.n <= @end-@start
    ) s
    where @end >= s.n
    
    GO
    
    0 讨论(0)
  • 2020-11-22 10:40

    Update for SQL 2017 and later: If the sequence you desire is < 8k then this will work:

    Declare @start_num int = 1000
    ,   @end_num int = 1050
    
    Select [number] = @start_num + ROW_NUMBER() over (order by (Select null))
    from string_split(replicate(' ',@end_num-@start_num-1),' ')
    
    0 讨论(0)
  • 2020-11-22 10:41

    This only works for sequences as long as some application table has rows. Assume I want sequence from 1..100, and have application table dbo.foo with column (of numeric or string type) foo.bar:

    select 
    top 100
    row_number() over (order by dbo.foo.bar) as seq
    from dbo.foo
    

    Despite its presence in an order by clause, dbo.foo.bar does not have to have distinct or even non-null values.

    Of course, SQL Server 2012 has sequence objects, so there's a natural solution in that product.

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

    This completed for me in 36 seconds on our DEV server. Like Brian's answer, focusing on filtering to the range is important from within the query; a BETWEEN still tries to generate all the initial records prior to the lower bound even though it doesn't need them.

    declare @s bigint = 10000000
        ,   @e bigint = 20000000
    
    ;WITH 
    Z AS (SELECT 0 z FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)) T(n)),
    Y AS (SELECT 0 z FROM Z a, Z b, Z c, Z d, Z e, Z f, Z g, Z h, Z i, Z j, Z k, Z l, Z m, Z n, Z o, Z p),
    N AS (SELECT ROW_NUMBER() OVER (PARTITION BY 0 ORDER BY z) n FROM Y)
    
    SELECT TOP (1+@e-@s) @s + n - 1 FROM N
    

    Note that ROW_NUMBER is a bigint, so we can't go over 2^^64 (==16^^16) generated records with any method that uses it. This query therefore respects the same upper limit on generated values.

    0 讨论(0)
  • 2020-11-22 10:43
    declare @start int = 1000
    declare @end    int =1050
    
    ;with numcte  
    AS  
    (  
      SELECT @start [SEQUENCE]  
      UNION all  
      SELECT [SEQUENCE] + 1 FROM numcte WHERE [SEQUENCE] < @end 
    )      
    SELECT * FROM numcte
    
    0 讨论(0)
  • 2020-11-22 10:43

    This is what I do, it's pretty fast and flexible and not a lot of code.

    DECLARE @count  int =   65536;
    DECLARE @start  int =   11;
    DECLARE @xml    xml =   REPLICATE(CAST('<x/>' AS nvarchar(max)), @count);
    
    ; WITH GenerateNumbers(Num) AS
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY @count) + @start - 1
        FROM    @xml.nodes('/x') X(T)
    )
    SELECT  Num
    FROM    GenerateNumbers;
    

    Note that (ORDER BY @count) is a dummy. It doesn't do anything but ROW_NUMBER() requires an ORDER BY.

    Edit: I realized that the original question was to get a range from x to y. My script can be modified like this to get a range:

    DECLARE @start  int =   5;
    DECLARE @end    int =   21;
    DECLARE @xml    xml =   REPLICATE(CAST('<x/>' AS nvarchar(max)), @end - @start + 1);
    
    ; WITH GenerateNumbers(Num) AS
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY @end) + @start - 1
        FROM    @xml.nodes('/x') X(T)
    )
    SELECT  Num
    FROM    GenerateNumbers;
    
    0 讨论(0)
提交回复
热议问题