Случайная запись из таблицы базы данных (T-SQL) - PullRequest
75 голосов
/ 10 октября 2008

Есть ли краткий способ извлечь случайную запись из таблицы сервера sql?

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

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

Идеи

Ответы [ 5 ]

132 голосов
/ 10 октября 2008

Существует ли краткий способ извлечения случайной записи из таблицы сервера sql?

Да

SELECT TOP 1 * FROM table ORDER BY NEWID()

Объяснение

A NEWID() генерируется для каждой строки, а затем таблица сортируется по ней. Возвращается первая запись (то есть запись с «самым низким» GUID).

Примечания

  1. GUID генерируются в виде псевдослучайных чисел начиная с четвертой версии:

    UUID версии 4 предназначен для генерации UUID из действительно случайных или псевдослучайные числа.

    Алгоритм выглядит следующим образом:

    • Установите два старших значащих бита (биты 6 и 7) clock_seq_hi_and_reserved в ноль и единицу соответственно.
    • Установите четыре старших разряда (биты с 12 по 15) поле time_hi_and_version для 4-битного номера версии от Раздел 4.1.3.
    • Установить все остальные биты для случайного (или псевдослучайного) выбора значения.

    & mdash; Пространство имен URN универсального уникального идентификатора (UUID) - RFC 4122

  2. Альтернатива SELECT TOP 1 * FROM table ORDER BY RAND() не будет работать так, как можно подумать. RAND() возвращает одно значение для каждого запроса, поэтому все строки будут иметь одинаковое значение.

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

  4. Типичная производительность составляет менее 10 секунд для примерно 1 000 000 строк & mdash; конечно в зависимости от системы. Обратите внимание, что невозможно достичь индекса, поэтому производительность будет относительно ограниченной.

22 голосов
/ 26 августа 2012

Для больших таблиц вы также можете использовать TABLESAMPLE, чтобы избежать сканирования всей таблицы.

SELECT  TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()

ORDER BY NEWID по-прежнему требуется, чтобы не возвращать строки, которые появляются первыми на странице данных.

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

7 голосов
/ 10 октября 2008

Также попробуйте свой метод, чтобы получить случайный идентификатор между MIN (Id) и MAX (Id), а затем

SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid

Это всегда даст вам один ряд.

6 голосов
/ 16 декабря 2013

Если вы хотите выбрать большие данные, лучший способ, который я знаю, это:

SELECT * FROM Table1
WHERE (ABS(CAST(
    (BINARY_CHECKSUM
    (keycol1, NEWID())) as int))
    % 100) < 10

Источник: MSDN

0 голосов
/ 17 сентября 2013

Я пытался улучшить методы, которые я пробовал, и наткнулся на этот пост. Я понимаю, что это старый, но этот метод не указан. Я создаю и применяю тестовые данные; здесь показан метод для «адреса» в SP, вызываемый с @st (состоянием из двух символов)

Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5))
Insert Into ##TmpAddress(street, city, st, zip)
Select street, city, st, zip 
From tbl_Address (NOLOCK)
Where st = @st


-- unseeded RAND() will return the same number when called in rapid succession so
-- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation.

Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT)

Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip
From ##tmpAddress (NOLOCK)
Where id = @csr
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...