2012-03-30 10 views
2

データセットに2つのデータセットがあります。 1つの表には、「コストタイプ」というリストがあります。 IDと説明フィールドだけです。LINQと2つのデータセット

もう1つのデータテーブルはマスタテーブルであり、多数のレコードを持ち、そのうちの1つがコストタイプです。このデータテーブルで参照されていないコストタイプがあります。このデータベースにはコストという別の列があります。

私がしようとしているのは、費用の合計でコストタイプ別の要約を得ることです。しかし、私はすべてのコストタイプがマスタテーブルにない任意の値がゼロになることを記載したい。

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 

だから私はdatableで結果を見たいのですが(可能ならば)私は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」をどのように作成できるかを示すコードがあります。 –

答えて

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には2つのデータテーブルがあり、それらを使用したいと考えています。あなたの答えはどのようにそれに当てはまりますか? – Arion

+0

私の目標は、計算を実行するために 'Sum'を使う方法を示すことでした。しかし、より良い質問に答えるために、データテーブルを使用するようにコードを変更しました。 –

0

私は、他のものよりも単純なlinqを思いつきました。入力データを作成するコードのMartin Liversageに感謝します。各コストタイプは、私はあなただけのテーブルの上で1つのパスを必要と疑うグループ化を使用したのに対し、コストエントリテーブルを検索しますので、

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"]) 
    } 

); 

これは大きなテーブルの効率を失う可能性があります。個人的に私は(私の心に)よりシンプルなコードを好むでしょう。あなたのユースケースにも依存します。

関連する問題