2009-09-16 1 views
0

Мой коллега обнаружил поведение на SQL Server, о котором я не знал.Является ли это хорошим или плохим способом генерации случайных чисел для каждой записи?

CREATE VIEW dbo.vRandNumber AS 
SELECT RAND() as RandNumber 
GO 

CREATE FUNCTION dbo.RandNumber() RETURNS float AS 
RETURN (SELECT RandNumber FROM vRandNumber) 
GO 

DECLARE @mytable TABLE (id INT) 
INSERT INTO @mytable SELECT 1 
INSERT INTO @mytable SELECT 2 
INSERT INTO @mytable SELECT 3 

SELECT *, dbo.RandNumber() FROM @mytable 

Это кажется будет самым быстрым способом генерации случайных «» значения для каждой записи в наборе данных. Но я не совсем уверен, что это результат документированного поведения или использование причудливой конвергенции совпадений.

Будет вы используете что-то вроде этого?


РЕДАКТИРОВАТЬ

Это не вопрос о достоинствах функции RAND() сам, но использование комбинации ОДС/VIEW, чтобы заставить его пересчитать на каждой строке , (Использование только RAND() в конечном запросе вместо dbo.RandNumber() даст одинаковое значение для каждой записи.)

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

EDIT

Для SQL Server 2000+.

ответ

3

Я бы не сделал этого для части программного обеспечения, я хотел бы продолжить работу над будущими версиями SQL Server. Я нашел способ вернуть разные значения из RAND() для каждой строки в операторе select. Это открытие было 1) немного взломанным и 2) было сделано на SQL Server 2005. Он больше не работает на SQL Server 2008. Этот опыт заставляет меня лишний лечить полагаться на обман, чтобы получить rand(), чтобы вернуть случайное значение за ряд.

Кроме того, я считаю, что SQL Server может оптимизировать многократные вызовы UDF ... хотя это может измениться, поскольку теперь они позволяют некоторые недетерминированные функции.

Только для SQL Server 2005 способ принудительно выполнить rand() для каждой строки в операторе select. Не работает на SQL Server 2008. Не тестировался на любой версии до 2005:

create table #t (i int) 
insert into #t values (1) 
insert into #t values (2) 
insert into #t values (3) 

select i, case when i = 1 then rand() else rand() end as r 
from #t 

1 0.84923391682467 
2 0.0482397143838935 
3 0.939738172108974 

Кроме того, я знаю, что вы сказали, что вы не спрашивали о хаотичности рандов(), но я буду хорошим справочником есть: http://msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx. Он сравнивает rand() с newid() и rand (FunctionOf (PK, current datetime)).

+0

CHECKSUM (NEWID()) по крайней мере работает на SQL 2000+. Это зависит от определенного поведения, которое может быть удалено в патче SQL 2005. – gbn

0

Если бы мне пришлось выбрать случайное число для каждой строки в SQL, и вы могли бы доказать мне, что RAND() генерирует истинно случайных чисел ...

Да. Я бы, наверное, использовал что-то подобное.

1

Это зависит от того, для чего вам нужно случайное значение. Он также зависит от формата, что вам нужно значение в INTEGER, VARCHAR и т.д.

, если мне нужно сортировать строки в случайном порядке, я что-то вроде

SELECT * 
FROM [MyTable] 
ORDER BY newID() 

Аналогично, вы можете создать таблицу ints используя «функцию» идентификации SQL Server и выполнить аналогичный запрос, и это может привести к случайному числу.

Мой коллега нуждался в случайном целочисленном числе строк, поэтому он добавил вычисляемое поле в нашу таблицу и генерирует одно случайное число (целое число) для каждой строки, возвращаемой в запросе. Я не уверен, что рекомендую это; это вызвало проблемы в некоторых инструментах, но оно давало случайные целые числа для каждой таблицы. Затем мы могли бы объединить мое решение newid() и этой таблицы и получить набор случайных чисел, когда это необходимо.

Так что я возвращаюсь к . Можете ли вы рассказать о том, что вам нужно?

Update: Вот определение таблицы фрагмента мой коллега имел обыкновение иметь вычисляемый столбец возвращает другое случайное число в строку, каждый раз, когда таблица опрашивается:

CREATE TABLE [dbo].[Table](
    -- ... 
    [OrderID] [smallint] NOT NULL, --Not sure what happens if this is null 
    -- ... 
    [RandomizeID] AS (convert(int,(1000 * rand(([OrderID] * 100 * datepart(millisecond,getdate())))))), 
    -- ... 
) 
+0

В настоящее время это довольно академический, просто случай получения строк из записи набора случайным образом , В этом случае каждый раз нужны разные записи. Возможно, взвешен, но используя [weight] * dbo.RandNumber() дает это. Таким образом, просто введите способ получения случайно сгенерированной строки для каждой записи, которая отличается при каждом запросе таблицы. – MatBailie

+0

Я не указывал совместимость с sql-2000, но также (afaik) newID() не возвращает случайное число как таковое. Это не число (используется, например, для умножения веса), а не по-настоящему случайным, поскольку оно основано на времени, оборудовании и т. Д. Но тогда я не знаю, является ли это менее случайным, чем RAND() функция. – MatBailie

+0

Каков расчет, который ваш коллега вкладывает в расчетное поле? Я просто попытался использовать RAND() и получил другое значение для каждого исполнения, но такое же значение для каждой записи ... – MatBailie

0

Я бы не использовать это ,Насколько я знаю, RAND() использует системное время как семя и производит одни и те же значения, когда выполняется несколько раз подряд друг за другом. Например, попробуйте это:

SELECT *, 
      RAND() 
FROM  SomeTable 

RAND() предоставит вам одинаковое значение для каждой строки.

+1

Это поведение не связано с близостью времени. Это связано с тем, что RAND() выполняется один раз, а не один раз на запись. В этом примере также используется RAND(), но он запутывает его как для UDF, так и для просмотра. Таким образом, заставляя его пересчитывать каждый раз. В моем примере все три записи получают разные значения каждый раз. Насколько они случайны, я не уверен. Но они, конечно, не будут одинаковыми (за исключением случая). – MatBailie

+0

Мой запрос не совсем о достоинствах RAND(), но достоинства использования комбинации UDF/VIEW для принудительной перегруппировки для каждой строки. – MatBailie

+1

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

0

Вид и подход udf неуклюжий для меня: избыточные тривиальные объекты используют испорченную функцию.

Я хотел бы использовать CHECKSUM(NEWID()), чтобы сгенерировать случайное число (а не RAND() * xxx), или новый SQL Server 2008 CRYPT_GEN_RANDOM

+0

Не будет ли NEWID() разрешать константу так же, как RAND()? Таким образом, требуется сочетание view/udf? (Это комбинация view/udf, которая по сути является вопросом, позволяющая считать, что обычно считается постоянным выражением, которое должно быть переоценено для каждой записи.) – MatBailie

+0

NEWID() - * за вызов *, а не за оператор. Таким образом, это будет отличаться для каждой строки. – gbn

+0

Общий ответ: http://stackoverflow.com/search?q = newid + RAND + пользователь% 3A27535 – gbn