Это хороший или плохой способ генерирования случайных чисел для каждой записи? - PullRequest
0 голосов
/ 16 сентября 2009

Мой коллега обнаружил поведение в 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

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

Будет ли вы использовать что-то подобное?


EDIT

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

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

EDIT

Для SQL Server 2000 +.

Ответы [ 5 ]

3 голосов
/ 16 сентября 2009

Я бы не стал этого делать для части программного обеспечения, которую я хотел бы продолжить работу над будущими версиями SQL Server. Я нашел способ вернуть разные значения из RAND () для каждой строки в операторе выбора. Это открытие было 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

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

1 голос
/ 16 сентября 2009

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

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

SELECT *
FROM [MyTable]
ORDER BY newID()

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

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

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

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

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 голосов
/ 28 ноября 2009

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

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

0 голосов
/ 16 сентября 2009

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

SELECT    *, 
          RAND()
FROM      SomeTable

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

0 голосов
/ 16 сентября 2009

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

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

...