Existe uma maneira sucinta de recuperar um registro aleatório de uma tabela do servidor sql?
Eu gostaria de randomizar meus dados de teste de unidade, então estou procurando uma maneira simples de selecionar um id aleatório em uma tabela. Em inglês, o select seria "Selecione um id da tabela onde o id é um número aleatório entre o id mais baixo da tabela e o id mais alto da tabela."
Não consigo descobrir uma maneira de fazer isso sem ter que executar a consulta, testar um valor nulo e, em seguida, executar novamente se for nulo.
Ideias?
sql-server
tsql
random
Jeremy
fonte
fonte
Respostas:
sim
SELECT TOP 1 * FROM table ORDER BY NEWID()
Explicação
Um
NEWID()
é gerado para cada linha e a tabela é então classificada por ele. O primeiro registro é retornado (ou seja, o registro com o GUID "mais baixo").Notas
GUIDs são gerados como números pseudoaleatórios desde a versão quatro:
- Um namespace URN de identificador exclusivo universal (UUID) - RFC 4122
A alternativa
SELECT TOP 1 * FROM table ORDER BY RAND()
não funcionará como se imagina.RAND()
retorna um único valor por consulta, portanto, todas as linhas compartilharão o mesmo valor.Embora os valores GUID sejam pseudoaleatórios, você precisará de um PRNG melhor para os aplicativos mais exigentes.
O desempenho típico é inferior a 10 segundos para cerca de 1.000.000 de linhas - claro, dependendo do sistema. Observe que é impossível atingir um índice, portanto, o desempenho será relativamente limitado.
fonte
Em tabelas maiores, você também pode usar
TABLESAMPLE
para evitar a varredura de toda a tabela.SELECT TOP 1 * FROM YourTable TABLESAMPLE (1000 ROWS) ORDER BY NEWID()
O
ORDER BY NEWID
ainda é necessário para evitar apenas o retorno de linhas que aparecem primeiro na página de dados.O número a ser usado deve ser escolhido com cuidado para o tamanho e a definição da tabela e você pode considerar a lógica de repetição se nenhuma linha for retornada. A matemática por trás disso e por que a técnica não é adequada para mesas pequenas é discutida aqui
fonte
TOP 1
disso, não importa se as linhas na mesma página estão correlacionadas ou não. Você está escolhendo apenas um deles.Experimente também o seu método para obter um Id aleatório entre MIN (Id) e MAX (Id) e depois
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
Você sempre terá uma linha.
fonte
Se você deseja selecionar grandes volumes de dados, a melhor maneira que conheço é:
SELECT * FROM Table1 WHERE (ABS(CAST( (BINARY_CHECKSUM (keycol1, NEWID())) as int)) % 100) < 10
Fonte: MSDN
fonte
Eu estava procurando melhorar os métodos que experimentei e me deparei com este post. Sei que é antigo, mas esse método não está listado. Estou criando e aplicando dados de teste; isso mostra o método para "endereço" em um SP chamado com @st (estado de dois caracteres)
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
fonte
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)
Isso é explicado mais detalhadamente abaixo:
fonte