Добавить комментарий

Псевдослучайная последовательность в MSSQL

Использование встроенной функции rand() в запросах чревато проблемой получения последовательности одинаковых чисел. Например

CREATE TABLE T1 (id int);
GO
 
INSERT INTO T1
SELECT 1
UNION
SELECT 2
UNION
SELECT 3;
 
SELECT rand(), id FROM T1;

Выдает одинаковые значения
rand_value             id
---------------------- -----------
0,581556027773794      1
0,581556027773794      2
0,581556027773794      3
 
(3 row(s) affected)

Конечно, можно написать свою функцию - аналог rand(), используя один из алгоритмов генерации псевдослучайно последовательности. Но попробуем справиться встроенными средствами.

Если подавать на вход rand() в качестве параметра "seed" (инициализатора) псевдослучайные целые числа, то и на выходе мы получим псевдослучайную последовательность в диапазоне (0, 1). В качестве поставщика чисел для seed подойдет генератор GUID - функция newid(). Например так:

rand(abs(convert(int, convert(varbinary, newid()))))

Обернуть rand() в пользовательскую скалярную функцию нельзя согласно ограничениям MS SQL Server. Воспользуемся проекцией (view).

CREATE VIEW rand2 AS 
  SELECT rand(abs(convert(int, convert(varbinary, newid())))) AS rand_value;

Использовать проекцию в запросах можно так:
SELECT rand2.rand_value, id FROM T1 CROSS JOIN rand2;

или так:
SELECT (SELECT rand_value FROM rand2) AS rand_value, id FROM T1;

Повторив тест, получаем

rand_value             id
---------------------- -----------
0,349013124792225      1
0,780734712117597      2
0,488939877887713      3
 
(3 row(s) affected

За рамками заметки остается вопрос длины псевдослучайной последовательности. Оставляю этот вопрос читателю.