Comment sélectionner au hasard des lignes dans SQL?

226

J'utilise MSSQL Server 2005. Dans ma base de données, j'ai une table "customerNames" qui a deux colonnes "Id" et "Name" et env. 1000 résultats.

Je crée une fonctionnalité où je dois choisir 5 clients au hasard à chaque fois. Quelqu'un peut-il me dire comment créer une requête qui obtiendra 5 lignes aléatoires (Id et Nom) chaque fois que la requête est exécutée?

Prashant
la source
L'aléatoire n'est pas une exigence courante pour une base de données, j'ai été surpris de trouver un lien pour certains SQL
Paxic
2
Cela dépend de la quantité aléatoire que vous voulez. Voir: msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx pour la comparaison de NEW_ID par rapport à RAND ()
Shannon Severance

Réponses:

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

Cela dit, tout le monde semble venir sur cette page pour la réponse plus générale à votre question:

Sélection d'une ligne aléatoire dans SQL

Sélectionnez une ligne aléatoire avec MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

Sélectionnez une ligne aléatoire avec PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Sélectionnez une ligne aléatoire avec Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

Sélectionnez une ligne aléatoire avec IBM DB2

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

Sélectionnez un enregistrement aléatoire avec Oracle:

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

Sélectionnez une ligne aléatoire avec sqlite:

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1
Curtis Tasker
la source
3
+1 pour publier les réponses directement sur SO au lieu de créer un lien vers un site externe (comme la réponse acceptée) qui aurait pu baisser lorsque les futurs utilisateurs se pencheraient sur cette question.
Ray Zhou
17
Cela devient-il très coûteux sur de grandes tables, où chaque ligne obtient un nombre aléatoire, puis un grand ensemble de nombres aléatoires non indexés est trié?
Andrey
C'est peut-être évident pour la plupart des gens, mais ce n'était pas évident pour moi ... la requête suivante n'obtiendra pas de nouvelle valeur aléatoire pour chaque ligne: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - edit: je ne peux pas faire fonctionner le formatage dans les commentaires :(
Mir
Toi génie! Je vous déteste tellement parce que je ne l'ai pas vu avant d'être parti et d'avoir écrit une requête incroyablement longue avec des sous-requêtes et des numéros de ligne.
greenkode
5
Avertissement: pour les grandes bases de données, cette méthode aura de mauvaises performances. Pouvez-vous imaginer le temps qu'il faudra pour générer une valeur aléatoire pour chaque ligne si la base de données a un million d'entrées? Vous pouvez avoir plus d'informations et une meilleure alternative ici .
Francis Ngueukam
35
SELECT TOP 5 Id, Name FROM customerNames ORDER BY NEWID()
Cody Caughlan
la source
11

Si quelqu'un veut une solution PostgreSQL:

select id, name
from customer
order by random()
limit 5;
Barry Brown
la source
Cette réponse est bonne pour PostgreSQL, elle n'a pas besoin de la limite.
aliasbody
9

Peut - être que ce site vous sera utile.

Pour ceux qui ne veulent pas cliquer:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

la source
2
aurait dû au moins remplacer 1 par 5 :)
roman m
7

Il existe une belle solution spécifique à Microsoft SQL Server 2005 ici. Traite le problème où vous travaillez avec un grand ensemble de résultats (pas la question que je connais).

Sélection aléatoire de lignes dans une grande table http://msdn.microsoft.com/en-us/library/cc441928.aspx

JohnC
la source
5

Si vous avez une table avec des millions de lignes et que vous vous souciez des performances, cela pourrait être une meilleure réponse:

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

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

Tohid
la source
Notez que cela sélectionnera environ 10% des lignes du tableau. Si vous devez sélectionner un nombre exact de lignes, ou au moins N lignes, cette approche ne fonctionnera pas.
LarsH
4

Il s'agit d'une vieille question, mais tenter d'appliquer un nouveau champ (NEWID () ou ORDER BY rand ()) à une table avec un grand nombre de lignes coûterait trop cher. Si vous avez des ID incrémentiels et uniques (et que vous n'avez pas de trous), il sera plus efficace de calculer le X # d'ID à sélectionner au lieu d'appliquer un GUID ou similaire à chaque ligne, puis de prendre le X # supérieur.

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)

Si vous vouliez sélectionner beaucoup plus de lignes, je chercherais à remplir un #tempTable avec un ID et un tas de valeurs rand () puis à utiliser chaque valeur rand () pour mettre à l'échelle les valeurs min-max. De cette façon, vous n'avez pas à définir tous les paramètres @ randomId1 ... n. J'ai inclus un exemple ci-dessous en utilisant un CTE pour remplir la table initiale.

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;
RIanGillis
la source
@Protiguous, la modification que vous avez proposée a brisé la sélection aléatoire. L'utilisation de min () et max () appliquée à la table dbo.Tally64k ne permettrait pas à l'utilisateur de sélectionner une ligne avec un pk id> 65556.
RIanGillis
Le changement de nom de table était simplement un artefact du test. Le nom réel de la table n'a pas d'importance, tant que la bonne table est utilisée. min () et max () peuvent tous deux être interrogés dans une seule requête plutôt que deux, ce que j'essayais de montrer.
Protigu
@Protiguous Ah, je vois que maintenant, j'étais confus parce que vous avez utilisé le 0-65k pour faire le min-max mais pas plus tard. Après votre dernière édition, je voulais en fait vous poser des questions sur les implications des modifications que vous avez apportées en termes de performances, car l'optimisation des performances est l'un de mes intérêts et des décisions apparemment dénuées de sens, comme de quel côté du signe égal vous placez quelque chose, peuvent avoir un impact significatif - - La même chose s'appliquerait-elle aux 5 appels SET @ randomId ##? Ou est-ce différent parce qu'il ne s'agit pas d'une sélection à partir d'une table réelle?
RIanGillis
Je ne suis pas sûr de comprendre votre question. Demandez-vous pourquoi il y a 5 SET au lieu de seulement 1 SELECT @ id1 = rand (), @ id2 = rand () ..? C'est parce que plusieurs appels à une instruction rand () en 1 produiront le même résultat, d'où le SET séparé. (rand () sur SQL Server est une fonction déterministe, je crois.) Je voudrais suppose que 1 jeu sélectionné contre 5 est dans la plage des nanosecondes en termes de performances.
Protiguous
4
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 
Narendra
la source
Vieille question, mais cette réponse ne fonctionnait pas pour moi dans Oracle.
Bear
SELECT * FROM (SELECT * FROM table ORDER BY DBMS_RANDOM.VALUE) WHERE rownum <numéro; @Bear essayez ceci
Narendra
3

J'ai trouvé que cela fonctionnait mieux pour les mégadonnées.

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

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT)est aléatoire mais doit être ajouté TOP npour obtenir la taille d'échantillon correcte.

L'utilisation NEWID()est très lente sur les grandes tables.

Gamelle
la source
0

Comme je l'ai expliqué dans cet article , pour mélanger l'ensemble de résultats SQL, vous devez utiliser un appel de fonction spécifique à la base de données.

Notez que le tri d'un grand ensemble de résultats à l'aide d'une fonction RANDOM peut s'avérer très lent, alors assurez-vous de le faire sur de petits ensembles de résultats.

Si vous devez mélanger un ensemble de résultats volumineux et le limiter ensuite, il est préférable d'utiliser quelque chose comme OracleSAMPLE(N) ou TABLESAMPLEdans SQL Server ou PostgreSQL au lieu d'une fonction aléatoire dans la clause ORDER BY.

Donc, en supposant que nous ayons la table de base de données suivante:

entrez la description de l'image ici

Et les lignes suivantes du songtableau:

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

Oracle

Sur Oracle, vous devez utiliser la DBMS_RANDOM.VALUEfonction, comme illustré par l'exemple suivant:

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

Lors de l'exécution de la requête SQL susmentionnée sur Oracle, nous allons obtenir le jeu de résultats suivant:

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

Notez que les chansons sont répertoriées dans un ordre aléatoire, grâce à l' DBMS_RANDOM.VALUEappel de fonction utilisé par la clause ORDER BY.

serveur SQL

Sur SQL Server, vous devez utiliser la NEWIDfonction, comme illustré par l'exemple suivant:

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

Lors de l'exécution de la requête SQL susmentionnée sur SQL Server, nous allons obtenir le jeu de résultats suivant:

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

Notez que les chansons sont répertoriées dans un ordre aléatoire, grâce à l' NEWIDappel de fonction utilisé par la clause ORDER BY.

PostgreSQL

Sur PostgreSQL, vous devez utiliser la randomfonction, comme illustré par l'exemple suivant:

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

Lors de l'exécution de la requête SQL susmentionnée sur PostgreSQL, nous allons obtenir le jeu de résultats suivant:

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

Notez que les chansons sont répertoriées dans un ordre aléatoire, grâce à l' randomappel de fonction utilisé par la clause ORDER BY.

MySQL

Sur MySQL, vous devez utiliser la RANDfonction, comme illustré par l'exemple suivant:

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

Lors de l'exécution de la requête SQL susmentionnée sur MySQL, nous allons obtenir le jeu de résultats suivant:

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

Notez que les chansons sont répertoriées dans un ordre aléatoire, grâce à l' RANDappel de fonction utilisé par la clause ORDER BY.

Vlad Mihalcea
la source
0

Si vous utilisez une grande table et souhaitez accéder à 10% des données, exécutez la commande suivante: SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

Palash Mondal
la source