2011-02-06 14 views
0

Linqを使用して、指定した日付に最も近いレコードを選択するにはどうすればよいですか?これは、日付、製品ID、ロケーションID、および残高を持つトランザクションテーブル用です。これらの要件を考えるとLinqは日付に最も近いレコードを選択します

:いくつかは、指定された日

  • にあった場合

    • は、その日の最後のトランザクションを選択し
    • を表示指定日に何もなかった場合は、最も近い先行トランザクションを選択各倉庫には個別の取引があります
    • 複数の商品の残高を表示する - 各商品には個別の取引があります

    表データ:( - >倉庫 - >日付製品)または同様の

    // code 
    Id, TransDateTime, ProductId, WarehouseId, Balance 
    1, 1-Jan-2011 00:00, 1,   1,   100 
    2, 1-Jan-2011 00:00, 1,   2,   10 
    3, 2-Jan-2011 00:00, 1,   1,   150 
    4, 3-Jan-2011 00:00, 1,   2,   25 
    5, 3-Jan-2011 00:00, 2,   1,   333 
    6, 7-Jan-2011 00:00, 1,   1,   149 
    7, 7-Jan-2011 01:00, 1,   2,   30 
    8, 7-Jan-2011 02:00, 1,   2,   35 
    

    テストの日付と出力は

    Date: 1-Jan would output: 
    1, 1-Jan-2011 00:00, 1,   1,   100 
    2, 1-Jan-2011 00:00, 1,   2,   10 
    
    Date: 3-Jan would output: 
    3, 2-Jan-2011 00:00, 1,   1,   150 
    4, 3-Jan-2011 00:00, 1,   2,   25 
    5, 3-Jan-2011 00:00, 2,   1,   333 
    // product 1, warehouse 1 wasn't sold on the 3rd 
    // so the row from 2-Jan is returned 
    
    Date: 7-Jan would output: 
    5, 3-Jan-2011 00:00, 2,   1,   333 
    6, 7-Jan-2011 00:00, 1,   1,   149 
    9, 7-Jan-2011 02:00, 1,   2,   35 
    // product 2, warehouse 1 wasn't sold on the 7th 
    // so the row from 3-Jan is returned 
    // product 1, warehouse 2 was sold twice on the 7th 
    // so the later one is used 
    

    私はグループのグループ化を必要とするようになるだろうと思います。それは私のlinq能力を超えて!

  • 答えて

    5

    ステップ:
    1)inputDate
    2)各グループの製品および倉庫
    3)によって、トランザクションのグループの残りの後に起こったトランザクションをフィルタには、最新のトランザクションを見つける
    4)フォーマットの結果オブジェクト

    直接的実装:

    DateTime inputDate = ...; 
    var result = transactions 
          .Where(t => t.TransDateTime.Date <= inputDate.Date) 
          .GroupBy(t => new {t.ProductId, t.WarehouseId}) 
          .Select(x => new { 
           x.Key, 
           LastTransaction = x.OrderByDescending(t => t.TransDateTime).First(), 
          }) 
          .Select(x => new { 
           Id = x.LastTransaction.Id, 
           Date = x.LastTransaction.TransDateTime, 
           ProductId = x.Key.ProductId, 
           WarehouseId = x.Key.WarehouseId, 
           Balance = x.LastTransaction.Balance, 
          }); 
    

    いくつかの最適化が必要な場合は、実装を検討することができますMaxByIEnumerableの拡張方法は、x.OrderByDescending(t => t.TransDateTime).First()を置き換えます。 O(n log n)の代わりにO(n)であるため、多くのトランザクションがあるとパフォーマンスが向上します。 MaxBy実装はここで取ることができます:Simple LINQ question in C#

    +0

    +1これまで簡単に修正されたエラーが1つだけありました。「メソッド 'First'は最終的なクエリ操作としてのみ使用できます。このインスタンスの代わりに 'FirstOrDefault'メソッドを使用することを検討してください。 ' –

    +0

    @JK、それはlinq-to-sqlの仕様です。私はlinq-to-objectsでテストしていました。 – Snowbear