2012-03-30 89 views
2

我在數據集中有2個數據表。一個表有一個名爲CostTypes的列表。只是一個Id和說明字段。LINQ和2個數據表

另一個數據表是主表,有許多記錄,其中一列是成本類型。將會有在這個數據表中沒有引用的成本類型。這個數據庫中有另一列叫做成本。

我想要做的是按成本類型獲得總成本的總結。但我希望列出的所有成本類型的任何值都不在主表中爲零。

COSTTYPE表

Id, Description 

1,Marketing 

2,Sales 

3,Production 

4,Service 

Master table 

Id, Cost, CostTypeId 

1,10,1 

2,120,1 

3,40,3 

所以我想看看在確定年代的結果(如果可能的話),所以我可以綁定到datagridview的

Marketing 130 

Sales  0 

Production 40 

Service  0 

感謝幫助大家,這是我從答案中得出的結論 - 任何人都可以提出任何改進?

另外我怎樣才能將查詢1中的結果轉換爲數據?

var query1 = 
     from rowCT in costTypes.AsEnumerable() 
     from rowSTD in stdRates.AsEnumerable() 
       .Where(d => d.Field<int?>("CostTypeId") == rowCT.Field<int?>("CostTypeId")) 
       .DefaultIfEmpty() 
     group new { row0 = rowCT, row1 = rowSTD } 
     by rowCT.Field<string>("Description") into g 
     select new 
     { 
      g.Key, 
      Cost = g.Sum(x => x.row1 == null ? 0 : x.row1.Field<decimal>("Cost")), 
      TotalCost = g.Sum(x => x.row1 == null ? 0 : x.row1.Field<decimal>("TotalCost")), 
      TotalHours = g.Sum(x => x.row1 == null ? 0 : x.row1.Field<decimal>("TotalHours")), 
      TotalLabourCost = g.Sum(x => x.row1 == null ? 0 : x.row1.Field<decimal>("TotalLabourCost")) 
     } 
     ; 
+0

在我的答案我有代碼,演示如何創建一個'DataTable'作爲結果。 – 2012-03-30 13:18:21

回答

1

也許是這樣的:

測試數據:

DataTable dt=new DataTable(); 
dt.Columns.Add("Id",typeof(int)); 
dt.Columns.Add("Description",typeof(string)); 

dt.Rows.Add(1,"Marketing"); 
dt.Rows.Add(2,"Sales"); 
dt.Rows.Add(3,"Production"); 
dt.Rows.Add(4,"Service"); 

DataTable dt2=new DataTable(); 
dt2.Columns.Add("Id",typeof(int)); 
dt2.Columns.Add("Cost",typeof(int)); 
dt2.Columns.Add("CostTypeId",typeof(int)); 

dt2.Rows.Add(1,10,1); 
dt2.Rows.Add(2,120,1); 
dt2.Rows.Add(3,40,1); 

Linq查詢

var query=(
      from row in dt.AsEnumerable() 
      from row1 in dt2.AsEnumerable() 
        .Where (d =>d.Field<int>("Id")==row.Field<int>("Id")) 
        .DefaultIfEmpty() 
      group new{row,row1} 
      by row.Field<string>("Description") into g 
      select new 
      { 
       g.Key, 
       Cost=g.Sum (x =>x.row1==null?0:x.row1.Field<int>("Cost")) 
      } 
      ); 

結果

Key  Cost 
Marketing 10 
Sales  120 
Production 40 
Service 0 
0

可以使用Sum擴展方法來計算成本。它將返回0,如果集合爲空,這是你想要什麼:

var costTypes = new DataTable("CostTypes"); 
costTypes.Columns.Add("Id", typeof(Int32)); 
costTypes.Columns.Add("Description", typeof(String)); 
costTypes.Rows.Add(1, "Marketing"); 
costTypes.Rows.Add(2, "Sales"); 
costTypes.Rows.Add(3, "Production"); 
costTypes.Rows.Add(4, "Service"); 

var costEntries = new DataTable("CostEntries"); 
costEntries.Columns.Add("Id", typeof(Int32)); 
costEntries.Columns.Add("Cost", typeof(Int32)); 
costEntries.Columns.Add("CostTypeId", typeof(Int32)); 
costEntries.Rows.Add(1, 10, 1); 
costEntries.Rows.Add(2, 120, 1); 
costEntries.Rows.Add(3, 40, 3); 

var costs = costTypes 
    .Rows 
    .Cast<DataRow>() 
    .Select(
    dr => new { 
     Id = dr.Field<Int32>("Id"), 
     Description = dr.Field<String>("Description") 
    } 
) 
    .Select(
    ct => new { 
     ct.Description, 
     TotalCost = costEntries 
     .Rows 
     .Cast<DataRow>() 
     .Where(ce => ce.Field<Int32>("CostTypeId") == ct.Id) 
     .Sum(ce => ce.Field<Int32>("Cost")) 
    } 
); 

結果是:

 
Description|TotalCost 
-----------+--------- 
Marketing |  130 
Sales  |  0 
Production |  40 
Service |  0 

您可以創建一個新的DataSet很簡單:

var costsDataTable = new DataTable("Costs"); 
costsDataTable.Columns.Add("Description", typeof(String)); 
costsDataTable.Columns.Add("TotalCost", typeof(Int32)); 
foreach (var cost in costs) 
    costsDataTable.Rows.Add(cost.Description, cost.TotalCost); 

如果在上面的代碼中由Where執行的線性搜索是一個問題,您可以通過預先創建查找表來提高性能:

var costEntriesLookup = costEntries 
    .Rows 
    .Cast<DataRow>() 
    .Select(
    ce => new { 
     Cost = ce.Field<Int32>("Cost"), 
     CostTypeId = ce.Field<Int32>("CostTypeId") 
    } 
) 
    .ToLookup(ce => ce.CostTypeId, ce => ce.Cost); 
var costs = costTypes 
    .Rows 
    .Cast<DataRow>() 
    .Select(
    dr => new { 
     Id = dr.Field<Int32>("Id"), 
     Description = dr.Field<String>("Description") 
    } 
) 
    .Select(
    ct => new { 
     ct.Description, 
     TotalCost = costEntriesLookup.Contains(ct.Id) 
     ? costEntriesLookup[ct.Id].Sum() 
     : 0 
    } 
); 
+0

我只是覺得你錯過了這一點。 OP有兩個數據表,他想使用它們。你的答案如何適用於此? – Arion 2012-03-30 11:40:10

+0

我的目標是演示如何使用Sum來執行計算。但是,爲了更好地回答我改變我的代碼以使用數據表的問題。 – 2012-03-30 11:56:00

0

我想出了LINQ的一個簡單的比特比其他人似乎使用。感謝Martin Liversage創建輸入數據的代碼。

var costTypes = new DataTable("CostTypes"); 
costTypes.Columns.Add("Id", typeof(Int32)); 
costTypes.Columns.Add("Description", typeof(String)); 
costTypes.Rows.Add(1, "Marketing"); 
costTypes.Rows.Add(2, "Sales"); 
costTypes.Rows.Add(3, "Production"); 
costTypes.Rows.Add(4, "Service"); 

var costEntries = new DataTable("CostEntries"); 
costEntries.Columns.Add("Id", typeof(Int32)); 
costEntries.Columns.Add("Cost", typeof(Int32)); 
costEntries.Columns.Add("CostTypeId", typeof(Int32)); 
costEntries.Rows.Add(1, 10, 1); 
costEntries.Rows.Add(2, 120, 1); 
costEntries.Rows.Add(3, 40, 3); 

var cte = costTypes.Rows.Cast<DataRow>(); 
var cee = costEntries.Rows.Cast<DataRow>(); 
var output = cte.Select(
ct => new { 
    Description = ct["Description"], 
    Sum = cee.Where(ce=>ce["CostTypeId"].Equals(ct["Id"])).Sum(ce=>(int)ce["Cost"]) 
    } 

); 

這可能會失去對較大的表效率,因爲每個成本類型將搜索成本條目表,而使用分組我懷疑你只需要一個傳過來的表。我個人更喜歡(在我看來)更簡單的代碼。它將取決於您的使用情況。