1

1 つのテーブルの複数の行の日付を比較する Linq クエリを作成したいと考えています。このテーブルは、アカウントの残高データについて Web サービスをポーリングするデータで構成されます。残念ながら、ポーリング間隔は 100% 決定論的ではありません。つまり、1 日あたり各アカウントに 0 から 1 の追加エントリが存在する可能性があります。

アプリケーションの場合、このデータを特定のフォーマットで再フォーマットする必要があります(以下の出力を参照)。サンプルデータとテーブルの説明を含めました。

必要な出力を生成する EF Linq クエリを手伝ってくれる人はいますか?

テーブル:

id アカウント ID
残高 測定時のアカウントで利用可能なクレジット
create_date データが取得された日時

テーブル名:Balances
フィールド: id (int)
フィールド: balance (bigint)
フィールド: create_date (datetime)

サンプルデータ:

ID 残高 create_date
3 40 2012-04-02 07:01:00.627
1 55 2012-04-02 13:41:50.427
2 9 2012-04-02 03:41:50.727
1 40 2012-04-02 16:21:50.027
1 49 2012-04-02 16:55:50.127
1 74 2012-04-02 23:41:50.627
1 90 2012-04-02 23:44:50.427
3 3 2012-04-02 23:51:50.827

3 -10 2012-04-03 07:01:00.627
1 0 2012-04-03 13:41:50.427
2 999 2012-04-03 03:41:50.727
1 50 2012-04-03 15:21:50.027
1 49 2012-04-03 16:55:50.127
1 74 2012-04-03 23:41:50.627
2 -10 2012-04-03 07:41:50.727
1 100 2012-04-03 23:44:50.427
3 0 2012-04-03 23:51:50.827

期待される出力:

id アカウント ID
date 行の日付を生成するために使用されたデータ コンポーネント
balance_last_measurement日付 の最後の測定時の残高 difference 日付
最初と最後の測定間の残高の差

  • 2012 年 4 月 2 日、id 2 には 1 つの測定値しかなく、差分値が最後の (そして唯一の) 測定値に等しく設定されます。
id date balance_last_measurement difference
1 2012-04-02 90 35
1 2012-04-03 100 10
2 2012-04-02 9 9
2 2012-04-03 -10 -19
3 2012-04-02 3 -37
3 2012-04-03 0 37

更新 2012-04-10 20:06

Raphaël Althaus からの回答は非常に優れていますが、元のリクエストで小さな間違いを犯しました。「期待される出力」の差分フィールドは、次のいずれかである必要があります。

  1. 前日の最後の測定値とその日の最後の測定値の差
  2. 前日がない場合は、その日の最初の測定値を使用し、最後の測定値を使用する必要があります

これはまったく可能ですか?それはかなり複雑なようですか?

4

2 に答える 2

1

そのようなことを試してみます。

var query = db.Balances
                .OrderBy(m => m.Id)
                .ThenBy(m => m.CreationDate)
                .GroupBy(m => new
                                  {
                                      id = m.Id,
                                      year = SqlFunctions.DatePart("mm", m.CreationDate),
                                      month = SqlFunctions.DatePart("dd", m.CreationDate),
                                      day = SqlFunctions.DatePart("yyyy", m.CreationDate)
                                  }).ToList()//enumerate there, this is what we need from db
                .Select(g => new
                                 {
                                     id = g.Key.id,
                                     date = new DateTime(g.Key.year, g.Key.month, g.Key.day),
                                     last_balance = g.Select(m => m.BalanceValue).LastOrDefault(),
                                     difference = (g.Count() == 1 ? g.First().BalanceValue : g.Last().BalanceValue - g.First().BalanceValue)
                                 });    
于 2012-04-10T14:38:01.453 に答える
0

まあ、おそらく最適化されていない解決策ですが、それが機能するかどうかを確認してください.

まず、結果クラスを作成します

public class BalanceResult
    {
        public int Id { get; set; }
        public DateTime CreationDate { get; set; }
        public IList<int> BalanceResults { get; set; }
        public int Difference { get; set; }

        public int LastBalanecResultOfDay {get { return BalanceResults.Last(); }}
        public bool HasManyResults {get { return BalanceResults != null && BalanceResults.Count > 1; }}
        public int DailyDifference { get { return HasManyResults ? BalanceResults.Last() - BalanceResults.First() : BalanceResults.First(); } }

    }

次に、クエリを少し変更します

var query = db.Balances
                .GroupBy(m => new
                                  {
                                      id = m.Id,
                                      year = SqlFunctions.DatePart("mm", m.CreationDate),
                                      month = SqlFunctions.DatePart("dd", m.CreationDate),
                                      day = SqlFunctions.DatePart("yyyy", m.CreationDate)
                                  }).ToList()//enumerate there, this is what we need from db
                .Select(g => new BalanceResult
                                 {
                                     Id = g.Key.id,
                                     CreationDate = new DateTime(g.Key.year, g.Key.month, g.Key.day),
                                     BalanceResults = g.OrderBy(l => l.CreationDate).Select(l => l.BalanceValue).ToList()
                                 }).ToList(); 

そして最後に

foreach (var balanceResult in balanceResults.ToList())
            {
                var previousDayBalanceResult = balanceResults.FirstOrDefault(m => m.Id == balanceResult.Id && m.CreationDate == balanceResult.CreationDate.AddDays(-1));
                balanceResult.Difference = previousDayBalanceResult != null ? balanceResult.LastBalanecResultOfDay - previousDayBalanceResult.LastBalanecResultOfDay : balanceResult.DailyDifference;
            }

示されているように、パフォーマンス(辞書の使用など)、コードの読みやすさはもちろん改善されるべきですが...それがアイデアです!

于 2012-04-10T19:04:52.663 に答える