2016-07-26 8 views
2

Мне нужно получить 10 случайных строк из таблицы каждый раз, но строки не должны повторяться при повторении запроса.Получить случайные данные с SQL Server, но не повторять значения

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

В настоящее время мой запрос для получения 10 строк в случайном порядке:

SELECT TOP 10 * 
FROM tablename 
ORDER BY NEWID() 

Но MSDN предложить этот запрос

SELECT TOp 10 * FROM Table1 
    WHERE (ABS(CAST(
    (BINARY_CHECKSUM(*) * 
    RAND()) as int)) % 100) < 10 

Для хорошей работы. Но этот запрос не возвращает постоянные строки. Не могли бы вы предложить что-то на этом

+0

Показать выборочные данные пожалуйста. – NEER

ответ

2

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

Простейшим решением, вероятно, будет сохранение уже полученных строк или их идентификаторов во временной таблице, а затем запрос во втором запросе ... where id not in (select id from temp_table).

+0

данные очень большие, как у нас есть 20000 строк и более, как мы можем хранить данные в таблице temp и запускать снова и снова, это падение производительности я прав? – Manikandan

+1

Да, это приведет к снижению производительности при добавлении записей во временную таблицу, но если вы хотите, чтобы результат был вам нужен, ваш единственный вариант - сохранить уже выбранные строки где-нибудь, может быть, таблица с индексом обеспечит вам достаточную производительность для вас? – Doliveras

+0

20 тыс. Строк не слишком много данных. Например. если ваши строки имеют идентификатор целочисленного типа, и вы сохраняете только идентификаторы используемых строк, что может означать, что ваша временная таблица может поместиться, возможно, в 100 КБ, что может быть легко кэшировано в памяти и быстро получить доступ даже без индексов. –

0

Как сказал Jiri Tousek, каждый запрошенный вами запрос должен знать, какие предыдущие запросы были возвращены.

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

Вы заполняете эту колонку случайными числами один раз.

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


Добавить колонку RandomNumber binary(8) на стол. Вы можете выбрать другой размер. Должно быть достаточно 8 байтов.

Заполните его случайными числами. Однажды.

UPDATE tablename 
SET RandomNumber = CRYPT_GEN_RANDOM(8) 

Создание индекса на RandomNumber колонке. Уникальный индекс. Если окажется, что повторяются случайные числа (что маловероятно для 20 000 строк и случайных чисел длиной 8 байтов), затем повторно создавайте случайные числа (запустите оператор UPDATE еще раз), пока все они не станут уникальными.

Запрос первые 10 случайных строки:

SELECT TOP(10) * 
FROM tablename 
ORDER BY RandomNumber 

Как перерабатывает/использовать эти 10 случайных строки запоминают последнее используемое случайное число. Лучший способ сделать это зависит от того, как вы обрабатываете эти 10 случайных строк.

DECLARE @VarLastRandomNumber binary(8); 
SET @VarLastRandomNumber = ... 
-- the random number from the last row returned by the previous query 

Запрос следующие 10 случайных строк:

SELECT TOP(10) * 
FROM tablename 
WHERE RandomNumber > @VarLastRandomNumber 
ORDER BY RandomNumber 

процесса их и помнить последний использовавшийся случайное число.

Повторите. В качестве бонуса вы можете запросить различное количество случайных строк на каждой итерации (она не должна быть 10 каждый раз).

+1

Жизнеспособный способ, если a) OP может изменить сама таблица, b) таблица стабильна в течение этого процесса (нет новые или удаленные строки), в) только один сеанс выполняет этот процесс за раз. ОП не представила каких-либо конкретных подробностей, поэтому мы действительно не знаем. –

0

, что я хотел бы сделать, это есть два новых поля, SELECTED (INT) и TimesSelected (целое число), то

UPDATE tablename SET SELECTED = 0; 

WITH CTE AS (SELECT TOP 10 * 
FROM tablename 
ORDER BY TimesSelected ASC, NEWID()) 
UPDATE CTE SET SELECTED = 1, TimesSelected = TimesSelected + 1; 

SELECT * from tablename WHERE SELECTED = 1; 

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

вы можете поставить индекс по ОТДЕЛЬНОМУ и сделать

UPDATE tablename SET SELECTED = 0 WHERE SELECTED = 1; -- for performance 
+0

Да, я думаю, что это сработает, как только запись будет выбрана и станет 1, она не может быть повторно выбрана до тех пор, пока все остальные записи не станут 1, когда это произойдет, некоторые записи станут 2, а затем будут неприемлемы, пока остальные не догонят – Cato

0

Самым элегантным решением, если вы делаете последовательные запросы в течение определенного периода времени, будут использовать курсор:

DECLARE rnd_cursor CURSOR FOR 
    SELECT col1, col2, ... 
    FROM tablename 
    ORDER BY NEWID(); 

OPEN rnd_cursor; 
FETCH NEXT FROM rnd_cursor; -- Repeat ten times 

Держите курсор открытым и продолжайте выборку строк по мере необходимости. Закройте курсор, когда вы сделали:

CLOSE rnd_cursor; 
DEALLOCATE rnd_cursor; 

Что касается второй части вашего вопроса, как только вы скачали последнюю строку, откройте новый курсор:

IF @@FETCH_STATUS <> 0 
BEGIN 
    CLOSE rnd_cursor; 
    OPEN rnd_cursor; 
END; 

 Смежные вопросы

  • Нет связанных вопросов^_^