2013-09-26 20 views
0

我有一個問題在不同的標準上過濾DataTable。我知道第一個where子句LINQ過濾器在表上符合幾個標準/ DateDifference

where row.Field<TimeSpan>("DateDifference") >= TimeSpan.Zero 

是爲什麼不符合第三個標準。有什麼方法可以更改我的查詢以滿足所有要求嗎?

  1. DateDifference應該是正數。
  2. 應該選擇最小的DateDifference。
  3. 所有InventoryChanges必須在結果中。因此,如果沒有正面的DateDiff,則允許使用DateDifference爲負數。應該選擇最小的DateDiff 。

    ArticleNo Article  Price PriceSet InventoryChange DateDifference StockDifference 
         1 Article A 10  01.01.2012 02.01.2012  1    -2 
         1 Article A 11  01.06.2012 02.01.2012  -151   -2 
         2 Article B 14  01.01.2012 05.01.2012  4    1 
         2 Article B 14  01.01.2012 04.10.2012  277    -3 
         2 Article B 13  01.06.2012 05.01.2012  -148   1 
         2 Article B 13  01.06.2012 04.10.2012  125    -3 
         3 Article C 144  01.04.2012 28.02.2012  -33    -1 
         3 Article C 124  01.05.2012 28.02.2012  -63    -1 
    
    My result:   
         1 Article A 10  01.01.2012 02.01.2012  1    -2 
         2 Article B 14  01.01.2012 05.01.2012  4    1 
         2 Article B 13  01.06.2012 04.10.2012  125    -3 
    
    What I want to have is a table where the last row, where there is no positive DateDifference, is added. 
    The row with the smallest DateDifference should be selected: 
         1 Article A 10  01.01.2012 02.01.2012  1    -2 
         2 Article B 14  01.01.2012 05.01.2012  4    1 
         2 Article B 13  01.06.2012 04.10.2012  125    -3 
         3 Article C 144  01.04.2012 28.02.2012  -33    -1 
    

我到目前爲止查詢:

var query = from row in InventoryChanges.AsEnumerable() 
        where row.Field<TimeSpan>("DateDifference") >= TimeSpan.Zero 
        group row by new 
        { 
         ArticleNo = row.Field<Int32>("ArticleNo"), 
         Article = row.Field<String>("Article"), 
         InventoryChange = row.Field<DateTime>("InventoryChange"), 
         StockDifference = row.Field<Int32>("StockDifference") 
        } 
        into grp 
        select new 
        { 
         ArticleNo = grp.Key.ArticleNo, 
         Article = grp.Key.Article, 
         InventoryChange = grp.Key.InventoryChange, 
         PriceSet = grp.Where(r => r.Field<TimeSpan>("DateDifference") == grp.Select(min => min.Field<TimeSpan>("DateDifference")).Min()) 
          .Select(r => r.Field<DateTime>("PriceSet")).FirstOrDefault(), 
         DateDifference = grp.Select(r => r.Field<TimeSpan>("DateDifference")).Min(), 
         StockDifference = grp.Key.StockDifference, 
         Price = grp.Where(r => r.Field<TimeSpan>("DateDifference") == grp.Select(min => min.Field<TimeSpan>("DateDifference")).Min()) 
          .Select(r => r.Field<Decimal>("Price")).FirstOrDefault(), 
        }; 

任何幫助表示讚賞!

DataTable InventoryChanges = new DataTable("InventoryChanges"); 

      InventoryChanges.Columns.Add("ArticleNo", typeof(Int32)); 
      InventoryChanges.Columns.Add("Article", typeof(String)); 
      InventoryChanges.Columns.Add("Price", typeof(Decimal)); 
      InventoryChanges.Columns.Add("PriceSet", typeof(DateTime)); 
      InventoryChanges.Columns.Add("InventoryChange", typeof(DateTime)); 
      InventoryChanges.Columns.Add("DateDifference", typeof(TimeSpan)); 
      InventoryChanges.Columns.Add("StockDifference", typeof(Int32)); 

      DataRow dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 1, "Article A", 10, new DateTime(2012, 1, 1), new DateTime(2012, 1, 2), new TimeSpan(1, 0, 0, 0), -2 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 1, "Article A", 11, new DateTime(2012, 6, 1), new DateTime(2012, 1, 2), new TimeSpan(-151, 0, 0, 0), -2 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 2, "Article B", 14, new DateTime(2012, 1, 1), new DateTime(2012, 1, 5), new TimeSpan(4, 0, 0, 0), 1 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 2, "Article B", 14, new DateTime(2012, 1, 1), new DateTime(2012, 10, 4), new TimeSpan(277, 0, 0, 0), -3 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 2, "Article B", 13, new DateTime(2012, 6, 1), new DateTime(2012, 1, 5), new TimeSpan(-148, 0, 0, 0), 1 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 2, "Article B", 13, new DateTime(2012, 6, 1), new DateTime(2012, 10, 4), new TimeSpan(125, 0, 0, 0), -3 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 3, "Article C", 144, new DateTime(2012, 4, 1), new DateTime(2012, 2, 28), new TimeSpan(-33, 0, 0, 0), -1 }; 
      InventoryChanges.Rows.Add(dr); 
      dr = InventoryChanges.NewRow(); 
      dr.ItemArray = new object[] { 3, "Article C", 124, new DateTime(2012, 5, 1), new DateTime(2012, 2, 28), new TimeSpan(-63, 0, 0, 0), -1 }; 
      InventoryChanges.Rows.Add(dr); 
+0

這將真正幫助,如果你提供的樣本數據的代碼,如果這是可行的。 'var tbl = new DataTable; tbl.Columns.Add(..); tbl.Rows.Add(...); ...' –

+0

從.csv文件讀取數據,並且動態創建DataTable。但是我會創建一個具有相同結構的DataTable。 – abeldenibus

+0

我們沒有在這裏採取正的DateDifference ...「where row.Field (」DateDifference「)> = TimeSpan.Zero」? –

回答

1

也許有更優雅的方式,但是這應該工作:

var query = InventoryChanges.AsEnumerable() 
.GroupBy(r => new 
{ 
    ArticleNo = r.Field<Int32>("ArticleNo"), 
    Article = r.Field<String>("Article"), 
    InventoryChange = r.Field<DateTime>("InventoryChange"), 
    StockDifference = r.Field<Int32>("StockDifference") 
}) 
.Select(grp => 
{ 
    IEnumerable<DataRow> rows = grp; 
    bool anyPositiveDateDiff = grp.Any(r => r.Field<TimeSpan>("DateDifference") >= TimeSpan.Zero); 
    if (anyPositiveDateDiff) 
     rows = grp.Where(r => r.Field<TimeSpan>("DateDifference") >= TimeSpan.Zero); 
    var firstRow = rows 
     .OrderBy(r => r.Field<TimeSpan>("DateDifference").Duration()).First();   
    return new 
    { 
     ArticleNo = grp.Key.ArticleNo, 
     Article = grp.Key.Article, 
     InventoryChange = grp.Key.InventoryChange, 
     PriceSet = firstRow.Field<DateTime>("PriceSet"), 
     DateDifference = rows.Min(r => r.Field<TimeSpan>("DateDifference")), 
     StockDifference = grp.Key.StockDifference, 
     Price = firstRow.Field<Decimal>("Price") 
    }; 
}); 

我檢查,如果有在bool anyPositiveDateDiff正時間跨度的組中的行。然後,我用積極的時間間隔行替換組的行。

另請注意,我已經簡化和改進了選擇你創建匿名類型的子查詢。

編輯這是根據您提供的樣本數據上面的查詢結果:

{ ArticleNo = 2, Article = Article B, InventoryChange = 05.01.2012 00:00:00, PriceSet = 01.01.2012 00:00:00, DateDifference = 4.00:00:00, StockDifference = 1, Price = 14 } 
{ ArticleNo = 2, Article = Article B, InventoryChange = 04.10.2012 00:00:00, PriceSet = 01.06.2012 00:00:00, DateDifference = 125.00:00:00, StockDifference = -3, Price = 13 } 
{ ArticleNo = 3, Article = Article C, InventoryChange = 28.02.2012 00:00:00, PriceSet = 01.04.2012 00:00:00, DateDifference = -63.00:00:00, StockDifference = -1, Price = 144 } 
+0

該解決方案非常接近,但當沒有正確的DateDifference時,它不會選擇最小的DateDifference。 – abeldenibus

+0

@abeldenibus:在'var firstRow = ...'編輯我的答案。 Imho你可以簡單地使用'TimeSpan.Duration'作爲'OrderBy'參數,因爲它是絕對的時間跨度。 –

+0

我只需要更改'PriceSet'TimeSpan中的Decimal並將DateDifference的選擇更改爲DateDifference = anyPositiveDateDiff? (r => r.Field (「DateDifference」)):rows.Max(r => r.Field (「DateDifference」)),'。你真的幫了我很多!向別人學習總是很好的。感謝您清理我的子查詢,以及;) – abeldenibus