1 votes

Regroupement par plages horaires en Linq

J'ai commencé à me plonger dans quelques requêtes linq pour la première fois aujourd'hui et j'ai des difficultés avec certaines des plus complexes. Je suis en train de construire une requête pour extraire des données d'une table afin de construire un graphique. Les colonnes des tables qui m'intéressent sont Id, Time et Value.

L'utilisateur va sélectionner une heure de début, une heure de fin et le nombre d'intervalles (points) à afficher sur le graphique. La colonne des valeurs sera en moyenne pour chaque intervalle.

Je peux le faire avec une requête linq pour chaque intervalle mais j'essaie de l'écrire en une seule requête pour ne devoir accéder à la base de données qu'une seule fois.

Jusqu'à présent, j'ai :

var timeSpan = endTime.Subtract(startTime);
var intervalInSeconds = timeSpan.TotalSeconds / intervals;

var wattList = (from t in _table
                where t.Id == id
                    && t.Time >= startTime
                    && t.Time <= endTime
                group t by  intervalInSeconds // C'est la partie avec laquelle j'ai des difficultés
                    into g
                    orderby g.Key 
                    select g.Average(a => a.Value))
                ).ToList();

Toute aide sur le regroupement par plages de temps sera la bienvenue.

1voto

Ben M Points 14458

J'ai fait cela moi-même pour exactement la même situation que vous décrivez.

Pour plus de rapidité, j'ai modifié la table des points de données de la base de données pour inclure une colonne de temps basée sur des entiers, SecondsSince2000, et j'ai travaillé avec cette valeur dans ma requête LINQ vers SQL. SecondsSince2000 est une colonne calculée définie comme suit :

datediff(second, dateadd(month,1200,0), ColonneHorairePointDeDonnees) PERSISTED

ColonneHorairePointDeDonnees est le nom de la colonne qui stocke l'heure du point de données. L'appel de fonction magique dateadd(month,1200,0) renvoie le 01-01-2000 à minuit, donc la colonne stocke le nombre de secondes depuis ce moment-là.

La requête LINQ vers SQL est alors beaucoup plus simple, et plus rapide :

int intervalleTemporelEnSecondes = 60;

var listeDeWatts = 
    (from t in _table
     where t.Id == id
           && t.Time >= startTime
           && t.Time <= endTime
     group t by t.SecondsSince2000 - (t.SecondsSince2000 % intervalleTemporelEnSecondes)
     into g
     orderby g.Key 
     select g.Average(a => a.Value))).ToList();

Si vous ne pouvez pas modifier votre base de données, vous pouvez toujours faire cela :

var tempsDeBase = new DateTime(2000, 1, 1);

var listeDeWatts = 
    (from t in _table
     where t.Id == id
           && t.Time >= startTime
           && t.Time <= endTime
     let secondesDepuis2000 = (int)(t.Time- tempsDeBase).TotalSeconds
     group t by secondesDepuis2000 - (secondesDepuis2000 % intervalleTemporelEnSecondes)
     into g
     orderby g.Key 
     select g.Average(a => a.Value))).ToList();

La requête sera assez plus lente.

0voto

Mike Comstock Points 1809

Découvrez cet exemple que j'ai écrit il y a un moment. Cela ressemble à ce que vous essayez de faire, mais je ne suis pas sûr s'il effectue le regroupement en SQL ou par .NET.

http://mikeinmadison.wordpress.com/2008/03/12/datetimeround/

0voto

Meta-Knight Points 10831

Peut-être que vous pouvez faire quelque chose comme :

var wattList = (from t in _table
                where t.Id == id
                   && t.Time >= startTime
                   && t.Time <= endTime
               ).GroupBy(x => (int) ((x.Time - startTime).TotalSeconds / intervalInSeconds))
                .Select(grp => grp.Average(x => x.Value));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X