How do I generate random number for each row in a TSQL Select?

前端 未结 19 977
逝去的感伤
逝去的感伤 2020-11-22 07:03

I need a different random number for each row in my table. The following seemingly obvious code uses the same random value for each row.

SELECT table_name,          


        
相关标签:
19条回答
  • 2020-11-22 07:24

    The Rand() function will generate the same random number, if used in a table SELECT query. Same applies if you use a seed to the Rand function. An alternative way to do it, is using this:

    SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]
    

    Got the information from here, which explains the problem very well.

    0 讨论(0)
  • 2020-11-22 07:28

    Do you have an integer value in each row that you could pass as a seed to the RAND function?

    To get an integer between 1 and 14 I believe this would work:

    FLOOR( RAND(<yourseed>) * 14) + 1
    
    0 讨论(0)
  • 2020-11-22 07:29

    If you need to preserve your seed so that it generates the "same" random data every time, you can do the following:

    1. Create a view that returns select rand()

    if object_id('cr_sample_randView') is not null
    begin
        drop view cr_sample_randView
    end
    go
    
    create view cr_sample_randView
    as
    select rand() as random_number
    go
    

    2. Create a UDF that selects the value from the view.

    if object_id('cr_sample_fnPerRowRand') is not null
    begin
        drop function cr_sample_fnPerRowRand
    end
    go
    
    create function cr_sample_fnPerRowRand()
    returns float
    as
    begin
        declare @returnValue float
        select @returnValue = random_number from cr_sample_randView
        return @returnValue
    end
    go
    

    3. Before selecting your data, seed the rand() function, and then use the UDF in your select statement.

    select rand(200);   -- see the rand() function
    with cte(id) as
    (select row_number() over(order by object_id) from sys.all_objects)
    select 
        id,
        dbo.cr_sample_fnPerRowRand()
    from cte
    where id <= 1000    -- limit the results to 1000 random numbers
    
    0 讨论(0)
  • 2020-11-22 07:29

    Try this:

    SELECT RAND(convert(varbinary, newid()))*(b-a)+a magic_number 
    

    Where a is the lower number and b is the upper number

    0 讨论(0)
  • 2020-11-22 07:34

    Take a look at SQL Server - Set based random numbers which has a very detailed explanation.

    To summarize, the following code generates a random number between 0 and 13 inclusive with a uniform distribution:

    ABS(CHECKSUM(NewId())) % 14
    

    To change your range, just change the number at the end of the expression. Be extra careful if you need a range that includes both positive and negative numbers. If you do it wrong, it's possible to double-count the number 0.

    A small warning for the math nuts in the room: there is a very slight bias in this code. CHECKSUM() results in numbers that are uniform across the entire range of the sql Int datatype, or at least as near so as my (the editor) testing can show. However, there will be some bias when CHECKSUM() produces a number at the very top end of that range. Any time you get a number between the maximum possible integer and the last exact multiple of the size of your desired range (14 in this case) before that maximum integer, those results are favored over the remaining portion of your range that cannot be produced from that last multiple of 14.

    As an example, imagine the entire range of the Int type is only 19. 19 is the largest possible integer you can hold. When CHECKSUM() results in 14-19, these correspond to results 0-5. Those numbers would be heavily favored over 6-13, because CHECKSUM() is twice as likely to generate them. It's easier to demonstrate this visually. Below is the entire possible set of results for our imaginary integer range:

    Checksum Integer: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
    Range Result:     0 1 2 3 4 5 6 7 8 9 10 11 12 13  0  1  2  3  4  5
    

    You can see here that there are more chances to produce some numbers than others: bias. Thankfully, the actual range of the Int type is much larger... so much so that in most cases the bias is nearly undetectable. However, it is something to be aware of if you ever find yourself doing this for serious security code.

    0 讨论(0)
  • 2020-11-22 07:34

    Use newid()

    select newid()
    

    or possibly this

    select binary_checksum(newid())
    
    0 讨论(0)
提交回复
热议问题