Что я делаю неправильно при использовании RAND () в MS SQL Server 2005? - PullRequest
3 голосов
/ 02 октября 2008

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

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

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

image

ОК, нет проблем, функция 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 ]

6 голосов
/ 02 октября 2008

Этот тип подхода (обозначен как ΤΖΩΤΖ) не гарантирует 10% выборки. Это даст только все строки, где Rand () имеет значение <.10, что не будет согласованным. </p>

Что-то вроде

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 в вашем запросе.

2 голосов
/ 02 октября 2008

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

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

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

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

1 голос
/ 02 октября 2008

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

select * from SomeTable
where rand(0*SomeTableID + cast(cast(newid() as binary(4)) as int)) <= 0.10
0 голосов
/ 26 января 2011

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

SELECT TOP 10 PERCENT * FROM schema.MyTable ORDER BY NEWID()
0 голосов
/ 02 октября 2008

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

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

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

...