Как вернуть случайные числа в виде столбца в SQL Server 2005? - PullRequest
21 голосов
/ 18 сентября 2008

Я выполняю SQL-запрос на SQL Server 2005, и в дополнение к 2 столбцам, запрашиваемым из базы данных, я также хотел бы вернуть 1 столбец случайных чисел вместе с ними. Я попробовал это:

select column1, column2, floor(rand() * 10000) as column3 
from table1

Что-то вроде работает, но проблема в том, что этот запрос возвращает одно и то же случайное число в каждой строке. Каждый раз, когда вы запускаете запрос, это другое число, но оно не меняется от строки к строке. Как я могу сделать это и получить новое случайное число для каждой строки?

Ответы [ 12 ]

40 голосов
/ 29 января 2009

Я понимаю, что это старая запись ... но вам не нужен просмотр.

select column1, column2, 
  ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 10000 as column3 
from table1
4 голосов
/ 30 января 2009

ПРЕДУПРЕЖДЕНИЕ

Ответ Адама , включающий представление, очень неэффективен, и для очень больших наборов может вынимать вашу базу данных на долгое время, я настоятельно рекомендую не использовать ее на регулярной основе или в ситуациях, когда вам нужно заполнить большие столы в производстве.

Вместо этого вы можете использовать этот ответ .

Доказательство:

CREATE VIEW vRandNumber
AS
SELECT RAND() as RandNumber

go 

CREATE FUNCTION RandNumber()
RETURNS float
AS
  BEGIN
  RETURN (SELECT RandNumber FROM vRandNumber)
  END

go 

create table bigtable(i int)

go 

insert into bigtable 
select top 100000 1 from sysobjects  a
join sysobjects b on 1=1

go 

select cast(dbo.RandNumber() * 10000 as integer) as r into #t from bigtable 
-- CPU (1607) READS (204639) DURATION (1551)

go

select ABS(CAST(CAST(NEWID() AS VARBINARY) AS int)) % 10000 as r  into #t1 
from bigtable
-- Runs 15 times faster - CPU (78) READS (809) DURATION (99)

Трассировка профилировщика:

альтернативный текст http://img519.imageshack.us/img519/8425/destroydbxu9.png

Это доказательство того, что материал достаточно случайный для чисел от 0 до 9999

-- proof that stuff is random enough 
select avg(r) from #t
-- 5004
select STDEV(r) from #t
-- 2895.1999 

select avg(r) from #t1
-- 4992
select STDEV(r) from #t1
-- 2881.44 


select r,count(r) from #t
group by r 
-- 10000 rows returned 

select r,count(r) from #t1
group by r 
-- 10000 row returned 
3 голосов
/ 07 декабря 2010
select RAND(CHECKSUM(NEWID()))
3 голосов
/ 18 сентября 2008

Ответ Адама работает очень хорошо, поэтому я отметил его как принятый. Пока я ждал ответа, я также нашел эту запись в блоге несколькими другими (чуть менее случайными) методами. Метод Кабоинга был среди них.

http://blog.sqlauthority.com/2007/04/29/sql-server-random-number-generator-script-sql-query/

1 голос
/ 26 апреля 2013

Я использую c # для работы со случайными числами. Это намного чище. У меня есть функция, которую я использую, чтобы вернуть список случайных чисел и уникальный ключ, затем я просто присоединяюсь к uniqueKey по номеру строки. Поскольку я использую c #, я могу легко указать диапазон, в который должны попадать случайные числа.

Вот шаги для создания функции: http://www.sqlwithcindy.com/2013/04/elegant-random-number-list-in-sql-server.html

Вот как выглядит мой запрос:

SELECT 
   rowNumber, 
   name, 
   randomNumber
FROM dbo.tvfRandomNumberList(1,10,100) 
INNER JOIN (select ROW_NUMBER() over (order by int_id) as 'rowNumber', name from client        
            )as clients
ON clients.rowNumber = uniqueKey
1 голос
/ 13 ноября 2009

Этот фрагмент, по-видимому, является разумной заменой rand() в том смысле, что он возвращает число с плавающей запятой между 0,0 и 1,0. Он использует только последние 3 байта, предоставленные newid(), поэтому общая случайность может немного отличаться от преобразования в VARBINARY, затем INT, а затем изменение из рекомендованного ответа. У меня не было возможности проверить относительную производительность, но, кажется, достаточно быстро (и достаточно случайно) для моих целей.

SELECT CAST(SubString(CONVERT(binary(16), newid()), 14, 3) AS INT) / 16777216.0 AS R
1 голос
/ 03 августа 2009

Согласно моему тестированию, ответ выше не генерирует значение 10000 когда-либо. Это, вероятно, не является большой проблемой, когда вы генерируете случайное число от 1 до 10000, но тот же алгоритм от 1 до 5 будет заметен. Добавьте 1 к вашему моду.

1 голос
/ 18 сентября 2008

newid () я считаю очень ресурсоемким. я вспоминаю, как пробовал этот метод на таблице из нескольких миллионов записей, и производительность была не такой хорошей, как у rand ().

1 голос
/ 18 сентября 2008

Вы можете рассмотреть возможность генерации UUID вместо случайного числа с помощью функции newid. Они гарантированно будут уникальными при каждом создании, тогда как существует значительная вероятность того, что некоторое дублирование произойдет с простым случайным числом (и в зависимости от того, для чего вы его используете, может привести к феноменально трудной для отладки ошибке на более позднем этапе)

1 голос
/ 18 сентября 2008

Запрос

select column1, column2, cast(new_id() as varchar(10)) as column3 
from table1
...