2009-08-17 4 views
1

Je me suis retrouvé coincé dans certaines requêtes linq pour la première fois aujourd'hui et je suis aux prises avec certaines des plus compliquées. Je construis une requête pour extraire des données d'une table pour construire un graphique. Les colonnes colonnes qui m'intéressent sont Id, Time et Valeur.Regroupement par plage horaire dans Linq

L'utilisateur sélectionnera une heure de début, une heure de fin et le nombre d'intervalles (points) à représenter graphiquement. La colonne de valeur sera moyennée pour chaque intervalle.

Je peux le faire avec une requête linq pour chaque intervalle, mais j'essaie de l'écrire dans une requête, donc je n'ai besoin d'aller à la base de données qu'une seule fois.

Jusqu'à présent, j'ai obtenu:

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 // This is the bit I'm struggling with 
        into g 
        orderby g.Key 
        select g.Average(a => a.Value)) 
       ).ToList(); 

Toute aide sur le regroupement sur des plages horaires seront les bienvenus.

Répondre

1

Je l'ai fait moi-même pour exactement la même situation que vous décrivez. Pour la vitesse, modification de la table de points de données de la base de données pour inclure une colonne d'heure basée sur un entier, SecondsSince2000, puis a travaillé avec cette valeur dans ma requête LINQ to SQL. SecondsSince2000 est une colonne calculée définie comme:

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

DataPointTimeColumn est le nom de la colonne qui stocke le temps du point de données. L'appel de la fonction magique dateadd(month,1200,0) renvoie 2000-01-01 à minuit, de sorte que la colonne stocke le nombre de secondes écoulées depuis cette heure.

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

int timeSlotInSeconds = 60; 

var wattList = 
    (from t in _table 
    where t.Id == id 
      && t.Time >= startTime 
      && t.Time <= endTime 
    group t by t.SecondsSince2000 - (t.SecondsSince2000 % timeSlotInSeconds) 
    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 le faire:

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

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

La requête être un peu plus lent.

+0

Inspiré merci – Magpie

0

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)); 
Questions connexes