Sélectionnez ligne au hasard à partir d'une table sqlite
J'ai un sqlite
table avec le schéma suivant:
CREATE TABLE foo (bar VARCHAR)
J'utilise cette table pour le stockage d'une liste de chaînes.
Comment puis-je sélectionner une ligne au hasard à partir de ce tableau?
- plusieurs stackoverflow.com/questions/4114940/...
Vous devez vous connecter pour publier un commentaire.
Ont un coup d'oeil à La sélection d'une Ligne au Hasard à partir d'une Table SQLite
SELECT a.foo FROM a JOIN b ON a.id = b.id WHERE b.bar = 2 ORDER BY RANDOM() LIMIT 1;
je reçois toujours la même ligne.Les solutions suivantes sont beaucoup plus rapides que anktastic (le count(*) coûte beaucoup, mais si vous pouvez mettre en cache, alors la différence n'est pas si grand), qui lui-même est beaucoup plus rapide que le "order by random()" lorsque vous avez un grand nombre de lignes, mais ils ont quelques inconvénients.
Si votre rowids sont plutôt emballé (ie. quelques suppressions), puis vous pouvez faire ce qui suit (à l'aide de
(select max(rowid) from foo)+1
au lieu demax(rowid)+1
offre de meilleures performances, comme expliqué dans les commentaires):Si vous avez des trous, parfois d'essayer de sélectionner une inexistant rowid, et select retourne un jeu de résultats vide. Si ce n'est pas acceptable, vous pouvez fournir une valeur par défaut comme ceci :
Cette deuxième solution n'est pas parfaite : la distribution de probabilité est plus élevée sur la dernière ligne (celle avec la plus haute rowid), mais si vous souvent ajouter des trucs à la table, il deviendra une cible en mouvement et de la distribution de probabilité devrait être beaucoup mieux.
Encore une autre solution, si vous sélectionnez des trucs aléatoires à partir d'une table avec beaucoup de trous, alors vous voudrez peut-être créer une table qui contient les lignes de la table d'origine triés dans un ordre aléatoire :
Puis, periodicalliy, re-remplir le tableau random_foo
Et pour sélectionner une ligne au hasard, vous pouvez utiliser ma première méthode (il n'y a pas de trous ici). Bien sûr, cette dernière méthode a des problèmes de concurrence d'accès, mais la re-construction de random_foo est un entretien de fonctionnement qui n'est pas susceptible de se produire très souvent.
Encore, encore d'une autre manière, que j'ai récemment trouvé sur un liste de diffusion, est de mettre un trigger sur supprimer pour déplacer la ligne avec la plus grande rowid dans le courant de ligne supprimée, de sorte que les trous sont de gauche.
Enfin, notez que le comportement de rowid et un integer primary key autoincrement n'est pas identique (avec rowid, lorsqu'une nouvelle ligne est insérée, max(rowid)+1 est choisi, wheras c'est plus de la valeur-jamais-vu+1 pour une clé primaire), de sorte que la dernière solution ne fonctionne pas avec un autoincrement dans random_foo, mais les autres méthodes.
SELECT max(rowid) + 1
sera une requête lente, cela nécessite un full table scan. sqlite seulement d'optimiser la requêteSELECT max(rowid)
. Ainsi, cette réponse pourrait être amélioré par:select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
Voir ce pour plus d'info: sqlite.1065341.n5.nabble.com/...Ce sujet:
puis de choisir un nombre aléatoire m dans [0, n) et
Vous pouvez même enregistrer le premier nombre (n) quelque part et de mettre à jour uniquement lorsque la base de données compte les modifications. De cette façon, vous n'avez pas à faire le SELECT COUNT chaque fois.
OFFSET
semble aller jusqu'en fonction de la taille de l'offset - ligne 2 est rapide, ligne 2 millions d'prend du temps, même lorsque toutes les données dans l'est de taille fixe, et il devrait être en mesure de demander directement à elle. Au moins, c'est ce à quoi il ressemble dans SQLite 3.7.13.Vous avez besoin de mettre "ordre ALÉATOIRE()" sur votre requête.
Exemple:
Nous allons voir un exemple complet
L'insertion de certaines valeurs:
Un défaut sélectionnez:
Une sélection aléatoire:
*Chaque fois que vous sélectionnez, l'ordre sera différent.
Si vous voulez retourner une seule ligne
*Chaque fois que vous sélectionnez, le retour sera différent.
Voici une modification de @ank la solution:
Cette solution fonctionne aussi pour les indices avec des lacunes, parce que nous avons un décalage aléatoire dans un intervalle [0, count).
MAX
est utilisé pour traiter une affaire avec table vide.Ici sont de simples résultats de test sur une table avec 16k lignes:
Je suis venu avec la solution suivante pour la de grandes bases de données sqlite3:
Enfin, vous ajoutez +1 à prévenir rowid égal à 0.