Quelle est la meilleure (et la plus rapide) façon de récupérer une ligne aléatoire en utilisant Linq to SQL lorsque j'ai une condition, par exemple un champ doit être vrai?
c#
.net
linq-to-sql
Julien Poulin
la source
la source
Réponses:
Vous pouvez le faire dans la base de données, en utilisant un faux UDF; dans une classe partielle, ajoutez une méthode au contexte de données:
Alors juste
order by ctx.Random()
; cela fera un ordre aléatoire sur le serveur SQL avec la permission deNEWID()
. c'est à direNotez que cela ne convient que pour les tables de petite à moyenne taille; pour les tables volumineuses, cela aura un impact sur les performances du serveur, et il sera plus efficace de trouver le nombre de lignes (
Count
), puis d'en choisir une au hasard (Skip/First
).pour l'approche de comptage:
la source
Un autre exemple pour Entity Framework:
Cela ne fonctionne pas avec LINQ to SQL. Le
OrderBy
est simplement abandonné.la source
EDIT: Je viens de remarquer que c'est LINQ to SQL, pas LINQ to Objects. Utilisez le code de Marc pour obtenir la base de données pour faire cela pour vous. J'ai laissé cette réponse ici comme un point d'intérêt potentiel pour LINQ to Objects.
Curieusement, vous n'avez pas besoin d'obtenir le décompte. Cependant, vous devez récupérer chaque élément à moins que vous n'obteniez le nombre.
Ce que vous pouvez faire, c'est conserver l'idée d'une valeur «actuelle» et du décompte actuel. Lorsque vous récupérez la valeur suivante, prenez un nombre aléatoire et remplacez le "courant" par "nouveau" avec une probabilité de 1 / n où n est le nombre.
Ainsi, lorsque vous lisez la première valeur, vous en faites toujours la valeur "courante". Lorsque vous lisez la deuxième valeur, vous pouvez en faire la valeur actuelle (probabilité 1/2). Lorsque vous lisez la troisième valeur, vous pouvez faire la valeur actuelle (probabilité 1/3), etc. Lorsque vous êtes à court de données, la valeur actuelle est aléatoire parmi toutes celles que vous lisez, avec une probabilité uniforme.
Pour appliquer cela avec une condition, ignorez simplement tout ce qui ne remplit pas la condition. La manière la plus simple de le faire est de ne considérer que la séquence «correspondante» pour commencer, en appliquant d'abord une clause Where.
Voici une mise en œuvre rapide. Je pense que ça va ...
la source
current
sera toujours défini sur le premier élément. Lors de la deuxième itération, il y a un changement de 50% selon lequel il sera défini sur le deuxième élément. À la troisième itération, il y a 33% de chances qu'il soit défini sur le troisième élément. L'ajout d'une instruction break signifierait que vous quitteriez toujours après avoir lu le premier élément, ce qui ne le rendrait pas du tout aléatoire.Un moyen efficace consiste à ajouter une colonne à vos données
Shuffle
qui est remplie avec un int aléatoire (lorsque chaque enregistrement est créé).La requête partielle pour accéder à la table dans un ordre aléatoire est ...
Cela effectue une opération XOR dans la base de données et trie les résultats de ce XOR.
Avantages: -
C'est l'approche utilisée par mon système domotique pour randomiser les listes de lecture. Il sélectionne une nouvelle graine chaque jour, donnant un ordre cohérent au cours de la journée (permettant des capacités de pause / reprise faciles), mais un regard neuf sur chaque playlist chaque nouveau jour.
la source
result = result.OrderBy(s => s.Shuffle ^ seed);
(c'est-à-dire pas besoin d'implémenter le XOR via les opérateurs ~, & et |).si vous voulez obtenir par exemple
var count = 16
des lignes aléatoires de la table, vous pouvez écrireici j'ai utilisé EF, et la table est un Dbset
la source
Si le but d'obtenir des lignes aléatoires est l'échantillonnage, j'ai parlé très brièvement ici d'une belle approche de Larson et al., Équipe Microsoft Research où ils ont développé un cadre d'échantillonnage pour Sql Server en utilisant des vues matérialisées. Il existe également un lien vers le document actuel.
la source
Explication: En insérant le guid (qui est aléatoire), l'ordre avec orderby serait aléatoire.
la source
Je suis venu ici en me demandant comment obtenir quelques pages aléatoires à partir d'un petit nombre d'entre elles, afin que chaque utilisateur obtienne 3 pages aléatoires différentes.
Ceci est ma solution finale, travaillant avec des requêtes avec LINQ sur une liste de pages dans Sharepoint 2010. C'est dans Visual Basic, désolé: p
Devrait probablement obtenir un profilage avant d'interroger un grand nombre de résultats, mais c'est parfait pour mon objectif
la source
J'ai une requête de fonction aléatoire contre
DataTable
s:la source
L'exemple ci-dessous appellera la source pour récupérer un décompte, puis appliquera une expression de saut sur la source avec un nombre compris entre 0 et n. La deuxième méthode appliquera l'ordre en utilisant l'objet aléatoire (qui ordonnera tout en mémoire) et sélectionnera le numéro passé dans l'appel de méthode.
la source
J'utilise cette méthode pour prendre des nouvelles aléatoires et ça fonctionne bien;)
la source
Utilisation de LINQ to SQL dans LINQPad en tant qu'instruction C #
Le SQL généré est
la source
Si vous utilisez LINQPad , passez en mode programme C # et procédez comme suit :
la source
Sélectionnez 2 lignes aléatoires
la source
A ajouter à la solution de Marc Gravell. Si vous ne travaillez pas avec la classe datacontext elle-même (parce que vous la procurez par proxy, par exemple pour simuler le datacontext à des fins de test), vous ne pouvez pas utiliser directement l'UDF défini: il ne sera pas compilé en SQL car vous ne l'utilisez pas dans un sous-classe ou classe partielle de votre classe de contexte de données réel.
Une solution de contournement à ce problème consiste à créer une fonction Randomize dans votre proxy, en l'alimentant avec la requête que vous souhaitez randomiser:
Voici comment vous l'utiliseriez dans votre code:
Pour être complet, voici comment implémenter cela dans le contexte de données FAKE (qui utilise en mémoire des entités):
la source