Avec Linq to SQL, comment trouver les valeurs min et max d’une colonne dans une table?

Je veux trouver le moyen le plus rapide d’obtenir le minimum et le maximum d’une colonne dans une table avec un aller-retour unique Linq to SQL. Donc, je sais que cela fonctionnerait en deux allers-retours:

int min = MyTable.Min(row => row.FavoriteNumber); int max = MyTable.Max(row => row.FavoriteNumber); 

Je sais que je peux utiliser group mais je n’ai pas group by clause group by article, je veux agréger toute la table! Et je ne peux pas utiliser le .Min sans grouper d’abord. J’ai essayé ceci:

 from row in MyTable group row by true into r select new { min = r.Min(z => z.FavoriteNumber), max = r.Max(z => z.FavoriteNumber) } 

Mais cette clause de groupe fou semble idiote, et le SQL qu’il crée est plus complexe qu’il ne le devrait.

Alors, y a-t-il un moyen de simplement extraire le code SQL correct?

EDIT: Ces gars ont aussi échoué: Linq to SQL: comment agréger sans groupe par? … si les concepteurs de LINQ ne contrôlent rien du tout s’il n’y a pas de réponse.

EDIT 2: j’ai examiné ma propre solution (avec la clause de groupe par constante sans sens) dans l’parsing du plan d’exécution de SQL Server Management Studio et j’ai l’impression qu’elle est identique au plan généré par:

 SELECT MIN(FavoriteNumber), MAX(FavoriteNumber) FROM MyTable 

aussi, à moins que quelqu’un puisse trouver une réponse plus simple ou tout aussi bonne, je pense que je dois la marquer comme une réponse donnée par moi-même. Pensées?

Comme indiqué dans la question, cette méthode semble générer un code SQL optimal. Par conséquent, même si elle semble un peu sinueuse dans LINQ, elle devrait être optimale en termes de performances.

 from row in MyTable group row by true into r select new { min = r.Min(z => z.FavoriteNumber), max = r.Max(z => z.FavoriteNumber) } 

Je n’ai pu trouver que celui-ci qui produit un SQL relativement propre mais pas vraiment efficace en comparant avec sélectionner min (val), max (val) dans le tableau:

 var r = (from min in items.OrderBy(i => i.Value) from max in items.OrderByDescending(i => i.Value) select new {min, max}).First(); 

le sql est

 SELECT TOP (1) [t0].[Value], [t1].[Value] AS [Value2] FROM [TestTable] AS [t0], [TestTable] AS [t1] ORDER BY [t0].[Value], [t1].[Value] DESC 

il existe toujours une autre option permettant d’utiliser une seule connexion pour les requêtes min et max (voir Plusieurs jeux de résultats actifs (MARS) ).

ou procédure stockée ..

Je ne sais pas encore comment le traduire en C # (j’y travaille)

Ceci est la version Haskell

 minAndMax :: Ord a => [a] -> (a,a) minAndMax [x] = (x,x) minAndMax (x:xs) = (min ax, max bx) where (a,b) = minAndMax xs 

La version C # devrait impliquer Aggregate certains comment (je pense).

Une requête LINQ to SQL est une expression unique. Ainsi, si vous ne pouvez pas exprimer votre requête dans une seule expression (ou si vous ne l’aimez pas une fois que vous l’êtes), vous devez examiner d’autres options.

Les procédures stockées, puisqu’elles peuvent avoir des déclarations, vous permettent d’accomplir cela en un seul aller-retour. Vous aurez soit deux parameters de sortie, soit un ensemble de résultats comportant deux lignes. Dans les deux cas, vous aurez besoin d’un code personnalisé pour lire le résultat de la procédure stockée.

(Personnellement, je ne vois pas la nécessité d’éviter deux allers-retours ici. Cela semble être une optimisation prématurée, d’autant plus que vous devrez probablement franchir des obstacles pour que cela fonctionne. Sans parler du temps que vous passerez à justifier votre décision. et expliquer la solution à d’autres développeurs.)

En d’autres termes: vous avez déjà répondu à votre propre question. “Je ne peux pas utiliser le .Min sans regrouper d’abord”, suivi de “cette clause de groupe fou semble stupide, et le SQL qu’il crée est plus complexe qu’il ne le faut”, sont des indices que le simple et facile à comprendre deux La solution aller-retour est la meilleure expression de votre intention (sauf si vous écrivez du code SQL personnalisé).

Vous pouvez sélectionner la table entière et faire vos opérations min et max en mémoire:

 var cache = // select * var min = cache.Min(...); var max = cache.Max(...); 

En fonction de la taille de votre jeu de données, cela peut être le moyen d’éviter de toucher votre firebase database plus d’une fois.