Como selecionar linhas aleatoriamente no SQL?


226

Estou usando o MSSQL Server 2005. No meu banco de dados, tenho uma tabela "customerNames" que possui duas colunas "Id" e "Name" e aprox. 1.000 resultados.

Estou criando uma funcionalidade em que preciso escolher 5 clientes aleatoriamente todas as vezes. Alguém pode me dizer como criar uma consulta que obterá 5 linhas aleatórias (ID e nome) toda vez que a consulta for executada?


Aleatória não é um requisito comum para um banco de dados, fiquei surpreso ao encontrar uma ligação para alguns SQL
Paxic

2
Depende de quanto aleatoriedade você deseja. Veja: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx para comparação de NEW_ID contra RAND ()
Shannon Severance

Respostas:


639
SELECT TOP 5 Id, Name FROM customerNames
ORDER BY NEWID()

Dito isto, todos parecem vir a esta página para obter uma resposta mais geral à sua pergunta:

Selecionando uma linha aleatória no SQL

Selecione uma linha aleatória com o MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Selecione uma linha aleatória com o PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Selecione uma linha aleatória com o Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Selecione uma linha aleatória com o IBM DB2

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Selecione um registro aleatório com o Oracle:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1

Selecione uma linha aleatória com sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1

3
+1 por postar as respostas diretamente no SO, em vez de vincular a um site externo (como a resposta aceita) que poderia ter sido desativado quando usuários futuros examinarem essa pergunta.
Ray Zhou

17
Isso se torna muito caro em tabelas grandes, em que cada linha obtém um número aleatório e, em seguida, um grande conjunto de números aleatórios não indexados é classificado?
21714 Andrey

Talvez isso seja óbvio para a maioria das pessoas, mas não era óbvio para mim ... a consulta a seguir não obterá um novo valor aleatório para cada linha: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - edit: não consigo fazer a formatação funcionar nos comentários :(
Mir

Você gênio! Eu te odeio tanto porque não vi isso até que escrevi uma consulta incrivelmente longa com subconsultas e números de linha.
greenkode

5
Aviso: Para bancos de dados grandes, esse método terá um desempenho ruim. Você pode imaginar o tempo que levará para gerar um valor aleatório para cada linha se o banco de dados tiver um milhão de entradas? Você pode obter mais informações e uma alternativa melhor aqui .
Francis Ngueukam


11

Caso alguém queira uma solução PostgreSQL:

select id, name
from customer
order by random()
limit 5;

Essa resposta é boa para o PostgreSQL, não precisa do limite.
aliasbody 14/01

9

Talvez este site seja útil.

Para aqueles que não querem clicar:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
deveria ter pelo menos substituído 1 por 5 :) #
romanm roman


5

Se você tem uma tabela com milhões de linhas e se preocupa com o desempenho, esta poderia ser uma resposta melhor:

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

https://msdn.microsoft.com/en-us/library/cc441928.aspx


Observe que isso selecionará aproximadamente 10% das linhas da tabela. Se você precisar selecionar um número exato de linhas, ou pelo menos N linhas, essa abordagem não funcionará.
Larsh

4

Essa é uma pergunta antiga, mas tentar aplicar um novo campo (NEWID () ou ORDER BY rand ()) a uma tabela com um grande número de linhas seria proibitivamente caro. Se você tiver IDs incrementais únicos (e não tiver nenhum furo), será mais eficiente calcular o número de Xs de ID a ser selecionado em vez de aplicar um GUID ou semelhante a cada linha e, em seguida, obter o número de X superior de.

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];

DECLARE @randomId1 int, @randomId2 int, @randomId3 int, @randomId4 int, @randomId5 int
SET @randomId1 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId2 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId3 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId4 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId5 = ((@maxValue + 1) - @minValue) * Rand() + @minValue

--select @maxValue as MaxValue, @minValue as MinValue
--  , @randomId1 as SelectedId1
--  , @randomId2 as SelectedId2
--  , @randomId3 as SelectedId3
--  , @randomId4 as SelectedId4
--  , @randomId5 as SelectedId5

select * from [TABLE] el
where el.id in (@randomId1, @randomId2, @randomId3, @randomId4, @randomId5)

Se você quisesse selecionar muito mais linhas, gostaria de preencher uma #tempTable com um ID e vários valores de rand () e, em seguida, usar cada valor de rand () para dimensionar para os valores min-max. Dessa forma, você não precisa definir todos os parâmetros @ randomId1 ... n. Incluí um exemplo abaixo usando um CTE para preencher a tabela inicial.

DECLARE @NumItems int = 100;

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];
DECLARE @range int = @maxValue+1 - @minValue;

with cte (n) as (
   select 1 union all
   select n+1 from cte
   where n < @NumItems
)
select cast( @range * rand(cast(newid() as varbinary(100))) + @minValue as int) tp
into #Nt
from cte;

select * from #Nt ntt
inner join [TABLE] i on i.id = ntt.tp;

drop table #Nt;

@Prigiguous, a edição que você propôs quebrou a seleção aleatória. Usando min () e max () aplicado à mesa de dbo.Tally64k não iria permitir ao utilizador seleccionar uma linha com uma ID de pk> 65556.
RIanGillis

A alteração do nome da tabela era simplesmente um artefato do teste. O nome da tabela real não importa, desde que a tabela correta seja usada. min () e max () podem ser consultados em uma consulta e não em duas, que é o que eu estava tentando mostrar.
Protíguo 14/01

@ Ah proigente, vejo que agora, fiquei confuso porque você usou o 0-65k ao fazer o min-max, mas não depois. Após a edição mais recente, eu realmente queria perguntar sobre as implicações de desempenho das alterações que você fez, já que o ajuste de desempenho é um dos meus interesses e decisões aparentemente sem sentido, como qual lado dos iguais significa que você coloca algo pode realmente ter um impacto significativo - - O mesmo se aplicaria às 5 chamadas SET @ randomId ##? Ou isso é diferente porque não está SELECIONANDO DE uma tabela real?
RIanGillis 15/01

Não sei se entendi sua pergunta. Você está perguntando por que existem 5 SET em vez de apenas 1 SELECT @ id1 = rand (), @ id2 = rand () ..? É porque várias chamadas para uma instrução rand () em 1 produzirão o mesmo resultado, daí o SET separado. (rand () no SQL Server é uma função determinística, acredito.) Suponho que 1 select vs 5 set esteja no intervalo de nanossegundos em termos de desempenho.
Protíguo 6/03

4
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 

Pergunta antiga, mas esta resposta não foi executada para mim no Oracle.
23718 Bear

SELECT * FROM (SELECT * FROM tabela ORDER BY DBMS_RANDOM.VALUE) WHERE rownum <número; @Bear try this
Narendra

3

Descobri que isso funciona melhor para big data.

SELECT TOP 1 Column_Name FROM dbo.Table TABLESAMPLE(1 PERCENT);

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT)é aleatório, mas é necessário adicionar o TOP npara obter o tamanho de amostra correto.

O uso NEWID()é muito lento em tabelas grandes.


0

Como expliquei neste artigo , para embaralhar o conjunto de resultados SQL, você precisa usar uma chamada de função específica do banco de dados.

Observe que a classificação de um grande conjunto de resultados usando uma função RANDOM pode ser muito lenta, portanto, faça isso em pequenos conjuntos de resultados.

Se você precisar embaralhar um grande conjunto de resultados e limitá-lo posteriormente, é melhor usar algo como o OracleSAMPLE(N) ou TABLESAMPLEno SQL Server ou no PostgreSQL, em vez de uma função aleatória na cláusula ORDER BY.

Portanto, supondo que tenhamos a seguinte tabela de banco de dados:

insira a descrição da imagem aqui

E as seguintes linhas na songtabela:

| id | artist                          | title                              |
|----|---------------------------------|------------------------------------|
| 1  | Miyagi & Эндшпиль ft. Рем Дигга | I Got Love                         |
| 2  | HAIM                            | Don't Save Me (Cyril Hahn Remix)   |
| 3  | 2Pac ft. DMX                    | Rise Of A Champion (GalilHD Remix) |
| 4  | Ed Sheeran & Passenger          | No Diggity (Kygo Remix)            |
| 5  | JP Cooper ft. Mali-Koa          | All This Love                      |

Oráculo

No Oracle, você precisa usar a DBMS_RANDOM.VALUEfunção, conforme ilustrado no seguinte exemplo:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY DBMS_RANDOM.VALUE

Ao executar a consulta SQL acima mencionada no Oracle, obteremos o seguinte conjunto de resultados:

| song                                              |
|---------------------------------------------------|
| JP Cooper ft. Mali-Koa - All This Love            |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Observe que as músicas estão sendo listadas aleatoriamente, graças à DBMS_RANDOM.VALUEchamada de função usada pela cláusula ORDER BY.

servidor SQL

No SQL Server, você precisa usar a NEWIDfunção, conforme ilustrado no seguinte exemplo:

SELECT
    CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY NEWID()

Ao executar a consulta SQL acima mencionada no SQL Server, obteremos o seguinte conjunto de resultados:

| song                                              |
|---------------------------------------------------|
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| JP Cooper ft. Mali-Koa - All This Love            |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |

Observe que as músicas estão sendo listadas aleatoriamente, graças à NEWIDchamada de função usada pela cláusula ORDER BY.

PostgreSQL

No PostgreSQL, você precisa usar a randomfunção, conforme ilustrado no seguinte exemplo:

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY random()

Ao executar a consulta SQL acima mencionada no PostgreSQL, obteremos o seguinte conjunto de resultados:

| song                                              |
|---------------------------------------------------|
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

Observe que as músicas estão sendo listadas aleatoriamente, graças à randomchamada de função usada pela cláusula ORDER BY.

MySQL

No MySQL, você precisa usar a RANDfunção, conforme ilustrado no exemplo a seguir:

SELECT
  CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY RAND()

Ao executar a consulta SQL acima mencionada no MySQL, obteremos o seguinte conjunto de resultados:

| song                                              |
|---------------------------------------------------|
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |

Observe que as músicas estão sendo listadas aleatoriamente, graças à RANDchamada de função usada pela cláusula ORDER BY.


0

Se você estiver usando uma tabela grande e quiser acessar 10% dos dados, execute o seguinte comando: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.