Obtendo Valor Aleatório no SQL Server com RAND()
Neste post você vai ver como gerar valores aleatórios no SQL Server usando a função RAND() do Transact-SQL: da sintaxe básica até um problema comum que pega muita gente de surpresa quando RAND() é usado em uma consulta com várias linhas.
Sintaxe da função RAND
RAND ( [ seed ] )
Argumento:
-
seed: valor inteiro (
tinyint,smallintouint) opcional, usado como semente do gerador. Se não for informado, o SQL Server usa uma semente aleatória automaticamente. Já quando um valor de seed é especificado, o resultado é sempre o mesmo para aquele valor.
O que a função RAND retorna
RAND() retorna um valor do tipo float, sempre entre 0 e 1:
SELECT RAND();
-- Exemplo de resultado: 0.494443
Uma observação importante: chamadas repetidas de RAND() com o mesmo seed retornam sempre o mesmo resultado. A consulta abaixo, por exemplo, sempre gera a mesma sequência de números para o mesmo seed:
SELECT RAND(100), RAND(), RAND();
Gerando um número inteiro com RAND
Para transformar o resultado de RAND() (que é sempre entre 0 e 1) em um número inteiro dentro de um intervalo, basta multiplicar pelo tamanho do intervalo desejado e converter com CAST ou FLOOR.
Número inteiro entre 0 e 9:
SELECT CAST(RAND() * 10 AS INT);
Número inteiro entre 0 e 19:
SELECT CAST(RAND() * 20 AS INT);
Para outras faixas, basta ajustar o multiplicador. De forma mais genérica, para gerar um número inteiro entre um valor mínimo e um valor máximo (incluindo os dois extremos), use:
SELECT FLOOR(RAND() * (@max - @min + 1) + @min);
Substituindo @min e @max pelos limites desejados, ou por variáveis declaradas antes da consulta.
O gotcha mais comum: RAND() repete o mesmo valor em todas as linhas
Esse é o ponto que mais confunde quem usa RAND() pela primeira vez em uma consulta real. Ao usar RAND() sem seed em um SELECT que retorna várias linhas, o SQL Server calcula o valor uma única vez para a consulta inteira, não uma vez por linha. O resultado é que todas as linhas recebem exatamente o mesmo número aleatório:
SELECT ProductID, RAND() AS ValorAleatorio
FROM Production.Product;
Nesse exemplo, toda a coluna ValorAleatorio sai com o mesmo valor repetido, o que raramente é o comportamento esperado.
Como resolver: RAND() com CHECKSUM(NEWID())
A forma mais comum de contornar isso é usar NEWID(), que gera um identificador único por linha, como semente de RAND():
SELECT ProductID, RAND(CHECKSUM(NEWID())) AS ValorAleatorio
FROM Production.Product;
Como NEWID() gera um valor diferente para cada linha, e CHECKSUM transforma esse valor em um inteiro para servir de seed, RAND() passa a calcular um número diferente para cada linha da consulta.
Gerando vários números aleatórios em um loop
Fora do contexto de uma consulta com múltiplas linhas, é possível gerar vários números aleatórios em sequência usando um WHILE:
DECLARE @Contador SMALLINT = 1;
WHILE @Contador < 5
BEGIN
SELECT RAND() AS NumeroAleatorio;
SET @Contador = @Contador + 1;
END;
Conclusão
RAND() é simples de usar para gerar um valor aleatório pontual, e com CAST ou FLOOR é fácil transformar esse valor em um inteiro dentro de qualquer faixa. O detalhe que realmente importa conhecer é o comportamento de RAND() em consultas com várias linhas: sem seed, ele repete o mesmo valor para todas as linhas, e a forma padrão de contornar isso é combinando RAND() com CHECKSUM(NEWID()).
Referência: Documentação oficial da função RAND (Microsoft Docs)