2013-09-26 1 views
0

다른 기준으로 DataTable을 필터링하는 데 문제가 있습니다. 나는 첫 번째 조항을 알고있다.여러 기준을 충족하는 테이블의 LINQ 필터/DateDifference

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

은 세 번째 기준이 충족되지 않는 이유이다. 모든 요구 사항을 충족시키기 위해 쿼리를 변경하는 방법이 있습니까?

  1. 날짜 차이는 양수 여야합니다.
  2. 가장 작은 DateDifference를 선택해야합니다.
  3. 모든 InventoryChanges가 결과에 있어야합니다. 음수가 음수 인 경우에는 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에서 긍정적 인 시간 범위와 그룹의 행이있는 경우. 그런 다음 그룹의 행을 양수 timespan 행으로 대체합니다.

또한 익명 형식을 만드는 위치에서 하위 쿼리를 단순화하고 향상 시켰습니다.

{ 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를 선택하지 않습니다. – abeldenibus

+0

@abeldenibus : 'var firstRow = ...'에서 내 대답을 수정했습니다. Imho 당신은 단순히'TimeSpan.Duration'을 절대 시간 간격 이후로'OrderBy' 인수로 사용할 수 있습니다. –

+0

'PriceSet'TimeSpan에서 Decimal을 변경하고 DateDifference 선택을 'DateDifference = anyPositiveDateDiff?'로 변경했습니다. (r => r.Field ("DateDifference")) : 행 .Max (r => r.Field ("DateDifference")),'. 당신은 정말 많이 도와 줬어! 항상 다른 사람들에게서 배우는 것이 좋습니다.) 내 하위 쿼리를 정리해 주셔서 감사합니다;) – abeldenibus