Есть ли краткий способ получить случайную запись из таблицы sql-сервера?
Я хотел бы рандомизировать свои данные модульного теста, поэтому ищу простой способ выбрать случайный идентификатор из таблицы. На английском языке выбор будет «Выбрать один идентификатор из таблицы, где идентификатор - случайное число между самым низким идентификатором в таблице и самым высоким идентификатором в таблице».
Я не могу найти способ сделать это без необходимости запускать запрос, проверять нулевое значение, а затем повторно запускать, если оно равно нулю.
Идеи?
sql-server
tsql
random
Джереми
источник
источник
Ответы:
да
SELECT TOP 1 * FROM table ORDER BY NEWID()
Объяснение
Для
NEWID()
каждой строки создается A, а затем таблица сортируется по нему. Возвращается первая запись (т. Е. Запись с «наименьшим» GUID).Ноты
Идентификаторы GUID генерируются как псевдослучайные числа начиная с четвертой версии:
- Пространство имен URN универсального уникального идентификатора (UUID) - RFC 4122
Альтернатива
SELECT TOP 1 * FROM table ORDER BY RAND()
не сработает, как можно было бы подумать.RAND()
возвращает одно значение для каждого запроса, поэтому все строки будут иметь одно и то же значение.Хотя значения GUID являются псевдослучайными, для более требовательных приложений вам понадобится лучший PRNG.
Типичная производительность составляет менее 10 секунд для примерно 1 000 000 строк - конечно, в зависимости от системы. Обратите внимание, что достичь индекса невозможно, поэтому производительность будет относительно ограниченной.
источник
На больших таблицах вы также можете использовать
TABLESAMPLE
для этого, чтобы избежать сканирования всей таблицы.SELECT TOP 1 * FROM YourTable TABLESAMPLE (1000 ROWS) ORDER BY NEWID()
По-
ORDER BY NEWID
прежнему требуется, чтобы не возвращать только строки, которые появляются первыми на странице данных.Число для использования необходимо тщательно выбирать в соответствии с размером и определением таблицы, и вы можете рассмотреть логику повторных попыток, если строка не возвращается. Здесь обсуждается математика, лежащая в основе этого, и почему этот метод не подходит для небольших таблиц.
источник
TOP 1
не имеет значения, коррелированы ли строки на одной странице или нет. Вы выбираете только один из них.Также попробуйте свой метод, чтобы получить случайный идентификатор между MIN (Id) и MAX (Id), а затем
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
Это всегда даст вам одну строку.
источник
Если вы хотите выбрать большие данные, лучший способ, который я знаю:
SELECT * FROM Table1 WHERE (ABS(CAST( (BINARY_CHECKSUM (keycol1, NEWID())) as int)) % 100) < 10
Источник: MSDN
источник
Я искал способы улучшить методы, которые пробовал, и наткнулся на этот пост. Я понимаю, что он старый, но этого метода нет в списке. Я создаю и применяю тестовые данные; здесь показан метод «адреса» в 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
источник
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)
Это дополнительно объясняется ниже:
источник