Come selezionare casualmente le righe in SQL?


226

Sto usando MSSQL Server 2005. Nel mio db ho una tabella "customerNames" che ha due colonne "Id" e "Nome" e ca. 1.000 risultati.

Sto creando una funzionalità in cui devo selezionare 5 clienti in modo casuale ogni volta. Qualcuno può dirmi come creare una query che otterrà 5 righe (ID e nome) casuali ogni volta che viene eseguita la query?


Il casuale non è un requisito comune per un database, sono stato sorpreso di trovare un collegamento per alcuni SQL
Paxic,

2
Dipende da quanta casualità vuoi. Vedere: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx per il confronto di NEW_ID rispetto a RAND ()
Shannon Severance

Risposte:


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

Detto questo, tutti sembrano venire a questa pagina per la risposta più generale alla tua domanda:

Selezione di una riga casuale in SQL

Seleziona una riga casuale con MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Seleziona una riga casuale con PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Seleziona una riga casuale con Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Seleziona una riga casuale con IBM DB2

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

Seleziona un record casuale con Oracle:

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

Seleziona una riga casuale con sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1

3
+1 per pubblicare le risposte direttamente su SO invece di collegarsi a un sito esterno (come la risposta accettata) che potrebbe non essere disponibile quando i futuri utenti esaminano questa domanda.
Ray Zhou,

17
Questo diventa molto costoso su tabelle di grandi dimensioni, dove ogni riga ottiene un numero casuale e quindi viene ordinato un set di numeri casuali di grandi dimensioni non indicizzato?
Andrey,

Questo è forse ovvio per la maggior parte delle persone, ma non era ovvio per me ... la seguente query non otterrà un nuovo valore casuale per ogni riga: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - modifica: non riesco a far funzionare la formattazione nei commenti :(
Mir

Genio! Ti odio così tanto perché non l'ho visto fino a quando non ero andato a scrivere una query follemente lunga con query secondarie e numeri di riga.
greenkode

5
Avviso: per i database di grandi dimensioni questo metodo avrà prestazioni scadenti. Riesci a immaginare il tempo necessario per generare un valore casuale per ogni riga se il database ha un milione di voci? Puoi avere maggiori informazioni e una migliore alternativa qui .
Francis Ngueukam,


11

Nel caso in cui qualcuno desideri una soluzione PostgreSQL:

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

Questa risposta è buona per PostgreSQL, non ha bisogno del limite.
aliasbody

9

Forse questo sito sarà di aiuto.

Per coloro che non vogliono fare clic:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
avrebbe dovuto sostituire almeno 1 con 5 :)
roman m


5

Se hai una tabella con milioni di righe e ti preoccupi delle prestazioni, questa potrebbe essere una risposta migliore:

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

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


Si noti che questo selezionerà circa il 10% delle righe nella tabella. Se è necessario selezionare un numero esatto di righe o almeno N righe, questo approccio non funzionerà.
LarsH,

4

Questa è una vecchia domanda, ma il tentativo di applicare un nuovo campo (NEWID () o ORDER BY rand ()) a una tabella con un gran numero di righe sarebbe proibitivamente costoso. Se si dispone di ID univoci incrementali (e non sono presenti buchi), sarà più efficiente calcolare il numero X di ID da selezionare anziché applicare un GUID o simile a ogni singola riga e quindi prendere il numero X superiore di.

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 si desidera selezionare molte più righe, si cercherebbe di popolare una #tempTable con un ID e un gruppo di valori rand (), quindi usando ciascun valore rand () per ridimensionare i valori min-max. In questo modo non è necessario definire tutti i parametri @ randomId1 ... n. Ho incluso un esempio di seguito usando un CTE per popolare la tabella iniziale.

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;

@Protiguous, la modifica che hai proposto ha interrotto la selezione casuale. L'uso di min () e max () applicati alla tabella dbo.Tally64k non consentirebbe all'utente di selezionare una riga con un ID pk> 65556.
RIanGillis

La modifica del nome della tabella era semplicemente un artefatto del test. Il nome effettivo della tabella non ha importanza, purché venga utilizzata la tabella corretta. min () e max () possono entrambi essere interrogati in una query anziché in due, che è quello che stavo cercando di mostrare.
Protiguous

@Protiguous Ah, lo vedo ora, ero confuso perché hai usato lo 0-65k quando facevi il min-max ma non più tardi. Dopo la tua modifica più recente, in realtà volevo chiederti quali fossero le implicazioni delle prestazioni delle modifiche che hai apportato, dato che l'ottimizzazione delle prestazioni è uno dei miei interessi e le decisioni apparentemente insignificanti come quale lato dell'uguale indicano che collochi qualcosa può effettivamente avere un impatto significativo - - La stessa cosa si applicherebbe alle 5 chiamate SET @ randomId ##? O è diverso perché non si sta SELEZIONANDO DA una tabella reale?
RIanGillis il

Non sono sicuro di aver capito la tua domanda. Stai chiedendo perché ci sono 5 SET invece di solo 1 SELECT @ id1 = rand (), @ id2 = rand () ..? È perché più chiamate a un'istruzione rand () in 1 produrranno lo stesso risultato, quindi il SET separato. (rand () su SQL Server è una funzione deterministica, credo.) Immagino che 1 set vs 5 sia nell'intervallo di nanosecondi in termini di prestazioni.
Protiguous

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

Vecchia domanda, ma questa risposta non ha funzionato per me in Oracle.
Orso

SELEZIONA * DA (SELEZIONA * DA tabella ORDINA PER DBMS_RANDOM.VALUE) DOVE rownum <numero; @Bear prova questo
Narendra il

3

Ho trovato che questo funziona meglio per i big data.

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

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) è casuale ma è necessario aggiungere il TOP n per ottenere la dimensione del campione corretta.

L'uso NEWID()è molto lento su tavoli di grandi dimensioni.


0

Come ho spiegato in questo articolo , per mescolare il set di risultati SQL, è necessario utilizzare una chiamata di funzione specifica del database.

Si noti che l'ordinamento di un set di risultati di grandi dimensioni utilizzando una funzione RANDOM potrebbe rivelarsi molto lento, quindi assicurarsi di farlo su set di risultati di piccole dimensioni.

Se devi mescolare un set di risultati di grandi dimensioni e limitarlo in seguito, è meglio usare qualcosa come OracleSAMPLE(N) o TABLESAMPLEin SQL Server o PostgreSQL invece di una funzione casuale nella clausola ORDER BY.

Quindi, supponendo che abbiamo la seguente tabella di database:

inserisci qui la descrizione dell'immagine

E le seguenti righe nella songtabella:

| 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                      |

Oracolo

Su Oracle, è necessario utilizzare la DBMS_RANDOM.VALUEfunzione, come illustrato dal seguente esempio:

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

Quando eseguiamo la suddetta query SQL su Oracle, otteniamo il seguente set di risultati:

| 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      |

Si noti che i brani vengono elencati in ordine casuale, grazie alla DBMS_RANDOM.VALUEchiamata di funzione utilizzata dalla clausola ORDER BY.

server SQL

Su SQL Server, è necessario utilizzare la NEWIDfunzione, come illustrato dal seguente esempio:

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

Quando eseguiamo la suddetta query SQL su SQL Server, otteniamo il seguente set di risultati:

| 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) |

Si noti che i brani vengono elencati in ordine casuale, grazie alla NEWIDchiamata di funzione utilizzata dalla clausola ORDER BY.

PostgreSQL

Su PostgreSQL, è necessario utilizzare la randomfunzione, come illustrato dal seguente esempio:

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

Quando eseguiamo la suddetta query SQL su PostgreSQL, otteniamo il seguente set di risultati:

| 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      |

Si noti che i brani vengono elencati in ordine casuale, grazie alla randomchiamata di funzione utilizzata dalla clausola ORDER BY.

MySQL

Su MySQL, è necessario utilizzare la RANDfunzione, come illustrato dal seguente esempio:

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

Quando eseguiamo la suddetta query SQL su MySQL, otterremo il seguente set di risultati:

| 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            |

Si noti che i brani vengono elencati in ordine casuale, grazie alla RANDchiamata di funzione utilizzata dalla clausola ORDER BY.


0

Se si utilizza una tabella di grandi dimensioni e si desidera accedere al 10 percento dei dati, eseguire questo comando: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.