2013-01-24 44 views
1

我有一個DataTable我想按摩到一個新的格式新的結構(這裏是它出來當連接到一個GridView等):項目的DataTable與LINQ的

<table cellspacing="0" rules="all" border="1" id="GridView1" style="border-collapse: collapse;"> 
     <tr> 
      <th scope="col"> 
       Line 
      </th> 
      <th scope="col"> 
       StartTime 
      </th> 
      <th scope="col"> 
       EndTime 
      </th> 
      <th scope="col"> 
       Attribute 
      </th> 
      <th scope="col"> 
       Value 
      </th> 
     </tr> 
     <tr> 
      <td> 
       Line1 
      </td> 
      <td> 
       24/01/2013 7:30:10 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       0 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line1 
      </td> 
      <td> 
       24/01/2013 7:30:10 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       ProductCategory 
      </td> 
      <td> 
       FFAC 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line1 
      </td> 
      <td> 
       24/01/2013 7:30:10 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Target 
      </td> 
      <td> 
       36.5 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line2 
      </td> 
      <td> 
       24/01/2013 7:26:50 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       69 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line2 
      </td> 
      <td> 
       24/01/2013 7:26:50 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       ProductCategory 
      </td> 
      <td> 
       FFAC 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line2 
      </td> 
      <td> 
       24/01/2013 7:26:50 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Target 
      </td> 
      <td> 
       55.5555582046509 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line3 
      </td> 
      <td> 
       24/01/2013 8:00:20 AM 
      </td> 
      <td> 
       24/01/2013 8:47:50 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       1475 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line3 
      </td> 
      <td> 
       24/01/2013 8:00:20 AM 
      </td> 
      <td> 
       24/01/2013 8:47:50 AM 
      </td> 
      <td> 
       ProductCategory 
      </td> 
      <td> 
       FFAC 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line3 
      </td> 
      <td> 
       24/01/2013 8:00:20 AM 
      </td> 
      <td> 
       24/01/2013 8:47:50 AM 
      </td> 
      <td> 
       Target 
      </td> 
      <td> 
       202.430557310581 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line4 
      </td> 
      <td> 
       24/01/2013 7:31:30 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       1384 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line4 
      </td> 
      <td> 
       24/01/2013 7:31:30 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       ProductCategory 
      </td> 
      <td> 
       FFAC 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line4 
      </td> 
      <td> 
       24/01/2013 7:31:30 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Target 
      </td> 
      <td> 
       3179.26381587982 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line5 
      </td> 
      <td> 
       24/01/2013 7:37:00 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       0 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line5 
      </td> 
      <td> 
       24/01/2013 7:37:00 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       ProductCategory 
      </td> 
      <td> 
       FHHT 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Line5 
      </td> 
      <td> 
       24/01/2013 7:37:00 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Target 
      </td> 
      <td> 
       92.6652171770756 
      </td> 
     </tr> 
     <tr> 
      <td> 
       P2_Bundler 
      </td> 
      <td> 
       24/01/2013 7:35:00 AM 
      </td> 
      <td> 
       24/01/2013 8:00:10 AM 
      </td> 
      <td> 
       Actual 
      </td> 
      <td> 
       7 
      </td> 
     </tr> 
    </table> 

我知道,如果記錄具有相同的行,開始和結束時間,記錄是相關的。

我想要做的是獲得由ProductCategory分組的實際值和目標值的總和。換句話說:

ProductCategory | Sum(Actual) | Sum(Target) 

FFAC   | 1000  | 2000 

FHHT   | 200   | 175 

任何指導將不勝感激!

問候,

克里斯

回答

2

你不會有任何的按摩這裏;)

你的DataTable會比電網代碼更加有用,但是要得到你想要的東西的結構你的DataTable,你應該這樣做。

var result = myDataTable.AsEnumerable() 
       .GroupBy(m => m.Field<string>("ProductCategory")) 
       .Select(g => new { 
        productCategory = g.Key, 
        sumActual = g.Sum(x => x.Field<decimal>("Actual")), 
        sumTarget = g.Sum(x => x.Field<decimal>("Target")) 
       }); 
+0

哇,你很快:)我得到一個錯誤g。鍵:'char'不包含'Key'的定義 –

+0

@ChrisHardie能顯示DataTable的結構嗎? –

+0

+1好按摩:) –

0

Oi,我認爲這會比預期的更困難,但最終變得更容易,我重寫了這個。您可以在行上執行分組,但是您只需查詢每個組中的行即可獲取ProductCategory。

首先,您將按主鍵進行分組,這種情況下我認爲是Line列。所以:

myDataTable.AsEnumerable() 
    .GroupBy(m => m.Field<string>("Line")) 

接下來,我們將不得不爲每個這些分組找到類別。由於每個分組是IEnumerable<T>,只需在將Attribute篩選爲ProductCategory並獲得第一個值之後執行Select即可。

... 
    .Select(g => new 
     { 
      ProductCategory = g.Where(r => r.Field<string>("Attribute") == "ProductCategory") 
         .Select(r => r.Field<string>("Value")) 
         .FirstOrDefault() ?? "No Category", 
      SumActual = g.Sum(x => x.Field<decimal>("Actual")), 
      SumTarget = g.Sum(x => x.Field<decimal>("Target")) 
     }) 

編輯:好了,所以現在我明白你說什麼,我的佔比在沒有ProductCategory屬性存在的情況下使用一點點「防禦性」的編碼。我原來的想法是正確的,因爲你將每個原始組(基於Line)分組到另外的組中。真的不是一個簡單的方法,而且選項也不太好。事實上,你必須對每個組進行分組,但爲了對組進行分組,你必須查詢組中的單個實體,然後根據另外兩個實體進行聚合(這使得在這裏使用LINQ非常困難)。

myDataTable.AsEnumerable() 
    .GroupBy(m => m.Field<string>("Line")) 
    .Select(g => new 
     { 
      ProductCategory = g.Where(r => r.Field<string>("Attribute") == "ProductCategory") 
         .Select(r => r.Field<string>("Value")) 
         .FirstOrDefault() ?? "No Category", 
      Actual = g.Where(r => r.Field<string>("Attribute") == "Actual") 
         .Select(r => 
          { 
           decimal d = 0m; 
           Decimal.TryParse(r.Field<string>("Value"), out d); 
           return d; 
          } 
         .FirstOrDefault(), 
      Target = g.Where(r => r.Field<string>("Attribute") == "Target") 
         .Select(r => 
          { 
           decimal d = 0m; 
           Decimal.TryParse(r.Field<string>("Value"), out d); 
           return d; 
          } 
         .FirstOrDefault() 
     }) 
    .GroupBy(n => n.ProductCategory) 
    .Select(g => new 
     { 
      ProductCategory = g.Key, 
      SumActual = g.Sum(x => x.Actual), 
      SumTarget = g.Sum(x => x.Target) 
     }) 

同樣,不是很漂亮......特別是因爲你的「值」欄中的字符串,你必須分析他們爲了獲得一個有意義的值(在這種情況下,總結了一些)。這裏的前提是您將所有記錄分組爲「塊」,然後將這些塊組合爲單個匿名對象。所以每個匿名對象都代表特定Line的所有數據行屬性/值對。從那裏,你只需根據你想要的鍵(在這種情況下是ProductCategory)進行分組,並執行你所需的聚合。

PS,我實際上在DB端使用PIVOT執行這個查詢。可能需要更多的設置,但是您可以設計系統來執行這種類型的數據處理/聚合工作,它可以處理這些工作,並保留前端CPU週期來處理更重要的事情。

+0

問題是「ProductCategory」不是DataTable的字段。只有「行」,「StartTime」,「EndTime」,「屬性」和「值」是有效的字段。 「ProductCategory」是Attribute字段的可能值。這裏的複雜性在於我不想按列分組,但我需要以某種方式表示某些字段值,以便我可以按這些字段進行分組。我想我可能需要創建一個佔位符集合,我可以將值推入,然後查詢。 –

+0

我的不好,那應該是由「Line」組合而不是「ProductCategory」。這就是我在上面的描述中寫的,但我想我的複印/麪食作業使我失敗了。 – SPFiredrake

+0

啊,我明白了。但是「實際」和「目標」不是原始數據表中的列,它們也可能是「屬性」列的值:) –