Что я делаю неправильно при использовании RAND() в MS SQL Server 2005?

Я пытаюсь выбрать случайную 10% -ную выборку из маленькой таблицы. Я думал, что просто использую функцию RAND() и выбираю те строки, где случайное число меньше 0.10:

SELECT * FROM SomeTable
WHERE SomeColumn='SomeCondition' AND
 RAND() < 0.10

Но вскоре я обнаружил, что RAND() всегда возвращает одинаковое число! Напоминает мне об этом мультфильме xkcd.

ОК, нет проблем, функция RAND принимает начальное значение. Я буду периодически запускать этот запрос, и я хочу, чтобы он дал разные результаты, если я запустил его в другой день, поэтому я засеваю его комбинацией даты и уникального идентификатора строки:

SELECT * FROM SomeTable
WHERE SomeColumn='SomeCondition' AND
 RAND(CAST(GETDATE) AS INTEGER) + RowID) < 0.10

Я до сих пор не получаю никаких результатов! Когда я показываю случайные числа, возвращаемые RAND, я обнаруживаю, что они все в узком диапазоне. Похоже, что получение случайного числа из RAND требует использования случайного семени. Если бы у меня было случайное семя в первую очередь, мне не понадобилось бы случайное число!

Я видел предыдущие обсуждения, связанные с этой проблемой:

Случайный сортировщик SQL Server Как запросить случайную строку в SQL?

Они мне не помогают. TABLESAMPLE работает на уровне страницы, что отлично подходит для большой таблицы, но не для небольшой, и похоже, что она применяется до предложения WHERE. TOP с NEWID не работает, потому что я не знаю заранее, сколько строк я хочу.

У кого-нибудь есть решение или хотя бы намек?

Изменить: Благодаря AlexCuse для решения , которое работает для моего конкретного случая. Теперь, к большему вопросу, как заставить RAND вести себя?

5 ответов

Этот тип подхода (показанный ΤΖΩΤΖΙΟΥ) не гарантирует 10% выборки. Он даст вам только все строки, где Rand() оценивается в <.10, которые не будут согласованы.

Что-то вроде

select top 10 percent * from MyTable order by NEWID()

сделает трюк.

edit: нет хорошего способа заставить RAND вести себя. Это то, что я использовал в прошлом (предупреждение kludge - это убивает вас, что вы не можете использовать Rand() в UDF)

CREATE VIEW RandView AS 
SELECT RAND() AS Val
GO
CREATE FUNCTION RandomFloat()
RETURNS FLOAT
AS
BEGIN
RETURN (SELECT Val FROM RandView)
END

Тогда у вас есть только select blah, dbo.RandomFloat() from table в вашем запросе.


Если в таблице есть столбец (возможно, даже столбец rowid), который является числовым в общем смысле, например целочисленный, с плавающей запятой или SQL-номером, попробуйте следующее:

SELECT * FROM SomeTable WHERE SomeColumn='SomeCondition' AND 0*rowid+RAND() < 0.10

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

Оптимизатор запросов виноват. Возможно, есть и другой способ, но я считаю, что это сработает для вас.


Это работает:

select * from SomeTable
where rand(0*SomeTableID + cast(cast(newid() as binary(4)) as int)) <= 0.10


Вы видели этот вопрос?

Как вернуть случайные числа в виде столбца в SQL Server 2005?

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


Это похоже на работу

SELECT TOP 10 PERCENT * FROM schema.MyTable ORDER BY NEWID()

licensed under cc by-sa 3.0 with attribution.