Почему RAND () не генерирует случайные числа? - PullRequest
9 голосов
/ 05 декабря 2011

Я отвечал на вопрос здесь и запустил мою SSMS, чтобы протестировать небольшой запрос перед его публикацией, но получил некоторые странные результаты. Вот запрос:

UPDATE Person
SET   Pos_X = Rand()
    , Pos_Y = Rand(id)

SELECT ID, Surname, Forename, Pos_X, Pos_Y FROM Person

А вот и результат:

1   Bloggs  Fred    0.332720913214171   0.713591993212924
2   Doe     Jane    0.332720913214171   0.713610626184182
3   Smith   Mary    0.332720913214171   0.71362925915544
4   Jones   Martha  0.332720913214171   0.713647892126698
5   Jones   Martha  0.332720913214171   0.713666525097956
6   Jones   Martha  0.332720913214171   0.713685158069215
7   Jones   Martha  0.332720913214171   0.713703791040473
8   Jones   Martha  0.332720913214171   0.713722424011731
9   Jones   Martha  0.332720913214171   0.713741056982989

Как я и ожидал, Рэнд без начального числа поместил один и тот же результат в каждую строку, но я надеялся, что ранд с начальным числом (например, числа от 1 до 9) будет лучше, чем упорядоченный список в пределах 0,0002 друг от друга. !

Вы получаете то же самое? Это звучит как что-то, что может застать врасплох.

Как я уверен, это будет актуально:

@@Version = 'Microsoft SQL Server 2005 - 9.00.5000.00 (Intel X86)   Dec 10 2010 10:56:29   Copyright (c) 1988-2005 Microsoft Corporation  Express Edition on Windows NT 6.1 (Build 7601: Service Pack 1)  '

Ответы [ 4 ]

15 голосов
/ 05 декабря 2011

RAND (Transact SQL) :

Возвращает псевдослучайное значение с плавающей запятой от 0 до 1, исключительное.

А:

Повторные вызовы RAND () с одинаковым начальным значением возвращают одинаковые результаты .

(выделение мое)

4 голосов
/ 05 декабря 2011

Пожалуйста, попробуйте выполнить запрос ниже, который всегда предоставляет желаемое случайное число.

SELECT RAND(CAST(RIGHT(CAST(CAST(CRYPT_GEN_RANDOM(4) 
                         AS INT) AS VARCHAR(100)), 1) AS INT))

Обновление : Согласно разговору, я изменил свой ответ, как показано ниже:

SELECT CAST(CRYPT_GEN_RANDOM(4) AS INT)
3 голосов
/ 05 декабря 2011

Функция CRYPT_GEN_RANDOM в ответе Элиаса заставила меня поработать над лучшим решением:

CREATE FUNCTION dbo.MyRAND(@Seed as bigint) RETURNS float(53) AS
BEGIN
    --Sample: SELECT dbo.MyRAND(DEFAULT), dbo.MyRAND(DEFAULT), dbo.MyRAND(12345) FROM ( SELECT 1 AS ID UNION SELECT 2 UNION SELECT 3 ) as ThreeRows
    DECLARE @Return as float(53)
    IF @Seed = 0
        SET @Return = (Cast(CRYPT_GEN_RANDOM(8) as bigint) + POWER(Cast(2 as float(53)), 63)) / POWER(2.0, 64)
    ELSE 
        SET @Return = (Cast(CRYPT_GEN_RANDOM(8, CAST(@Seed AS varbinary(8))) as bigint) + POWER(Cast(2 as float(53)), 63)) / POWER(2.0, 64)
    RETURN @Return
END

Это дает то же число с плавающей запятой между 0 и 1, что и RAND (), поэтому может появиться там, где начальное число отсутствует.не использовал.Он также будет вызываться для каждой строки, как показано в примере.Однако, в отличие от RAND, использование одного и того же начального числа не дает того же результата.


Примечание

Это больше не работает в:

Select @@Version 
    Microsoft SQL Server 2014 - 12.0.4100.1 (Intel X86) 
    Apr 20 2015 17:34:37 
    Copyright (c) Microsoft Corporation
    Developer Edition on Windows NT 6.1 <X64> (Build 7601: ) (WOW64)

как

Msg 443, Level 16, State 1, Procedure MyRAND, Line 10
Invalid use of a side-effecting operator 'Crypt_Gen_Random' within a function.
1 голос
/ 05 декабря 2011

, чтобы убедиться, что rand () вызывается отдельно для каждой строки, сделайте следующее:

create view wrapped_rand_view
as
    select rand( ) as random_value
go

create function wrapped_rand()
returns float as
begin
    declare @f float
    set @f = (select random_value from wrapped_rand_view)
    return @f
end

select 
    ThreeRows.ID, dbo.wrapped_rand() wrapped_rand
from 
    ( SELECT 1 AS ID UNION SELECT 2 UNION SELECT 3 ) as ThreeRows
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...