2016-04-06 18 views
1

私はデータテーブルで作業しています。それぞれのカテゴリに対して小計を取得し、総計を取得したいと考えています。categoryidでグループ化し、C#で各カテゴリの行の最後に小計を表示する方法linq

それぞれの行の最後に小計行を追加したいとします。私の問題は、私は最後のカテゴリの小計を取得しないということです。私はどこが間違っていたのか分かりません。 私を助けてくれる人はいらしてください。

必要な出力:

+------------+------------+------------+-----------+----------+-------+-----------+ 
|CategoryID | Category | Orgname | Penalties | Interest | Admin |TotalAmount| 
+------------+------------+------------+-----------+----------+-------+-----------+ 
| 1  | 1-Food  | Spar  | $10  | $0  | $15.3 | $20.3 | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| 1  | 1-Food  |Pick n’ Pay | $0  | $10  | $20 | $30  | 
+------------+------------+------------+-----------+----------+-------+-----------+ 
| Subtotal       | $10  | $10  | $30.3 | $50.3 | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| 2  | 2-Auto  | BMW  | $0  | $30  | $55 | $85  | 
| 2  | 2-Auto  | Toyota  | $9  | $0  | $14.5 | $23.5 | 
| 2  | 2-Auto  | Jaguar  | $22.8 | $8.2 | $50 | $81  | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| Subtotal       | $31.8  | $38.2 | $119.5| $189.5 | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| 3  | 3-Banking | Absa  | $0  | $40  | $155 | $190  | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| Subtotal       | $0  | $40  | $155 | $190  | 
+-------------------------+------------+-----------+----------+-------+-----------+ 
| Grand Total      | $41.8  | $88.2 | $304.8| $429,8 | 
+-------------------------+------------+-----------+----------+-------+-----------+ 

マイコード:

var query = (from _transaction in _entities.Transactions 
      join _cd in _entities.Organisations on _transaction.Refno equals _cd.Refno 
      join _category in _entities.Categorys on _transaction.CategoryID equals _category.CategoryID 
      group new { _trans = _transaction, cd = _cd, } 
      by new { _transaction.CategoryID, _transaction.Refno, _cd.Orgname, _category.Description } 
      into _group 
      orderby _group.Key.CategoryID 
      select new 
       { CategoryID = _group.Key.CategoryID, 
        Category = _group.Key.CategoryID + " - " + _group.Key.Description, 
        Refno = _group.Key.Refno, 
        Orgname = _group.Key.Orgname, 
        Penalties = _group.Sum(x => x._trans.Penalties), 
        Interest = _group.Sum(x => x._trans.Interest), 
        Admin = _group.Sum(x => x._trans.Admin), 
        TotalAmount = _group.Sum(x => x._trans.TotalAmount), 
       }); 
    DataTable dt = new DataTable(); 
    DataSet ds = new DataSet(); 
    ds.Tables.Add(query.CopyToDataTable()); ds.Tables[0].TableName = "Table1"; 
    dt = ds.Tables[0]; 

    //Get Subtotal 
    long _CategoryID = 0; double Admin = 0; double Interest = 0; 
    double Penalties = 0; double TotalAmount = 0; string Title = string.Empty; 
    for (int i = 0; i <= dt.Rows.Count - 1; i++) 
    { 
     if (i > 0) 
     { 
      if (dt.Rows[i]["Category"].ToString().ToLower() != dt.Rows[i - 1]["Category"].ToString().ToLower()) 
       { 
      dt.Rows.InsertAt(dt.NewRow(), i); 
      dt.Rows[i]["CategoryID"] = _CategoryID; 
      _CategoryID = 0; 
      dt.Rows[i]["Category"] = Title; 
      Title = string.Empty; 
      dt.Rows[i]["Admin"] = Admin; 
      Admin = 0; 
      dt.Rows[i]["Interest"] = Interest; 
      Interest = 0; 
      dt.Rows[i]["Penalties"] = Penalties; 
      Penalties = 0; 
      dt.Rows[i]["TotalAmount"] = TotalAmount; 
      TotalAmount = 0; 
      i++; 
      } 
     } 
     Title = "Subtotal"; 
     _CategoryID = Convert.ToInt64(dt.Rows[i]["CategoryID"]); 
     Admin += Convert.ToDouble(dt.Rows[i].IsNull("Admin") ? 0.0 : dt.Rows[i].Field<double>("Admin")); 
     Interest += Convert.ToDouble(dt.Rows[i].IsNull("Interest") ? 0.0 : dt.Rows[i].Field<double>("Interest")); 
     Penalties += Convert.ToDouble(dt.Rows[i].IsNull("Penalties") ? 0.0 : dt.Rows[i].Field<double>("Penalties")); 
     TotalAmount += Convert.ToDouble(dt.Rows[i].IsNull("TotalAmount") ? 0.0 : dt.Rows[i].Field<double>("TotalAmount")); 
    } 
    // Grand Total 
    var subtotal = query.GroupBy(x => x.CategoryID).Select(s => new 
    { 
     CategoryID = s.Key, 
     ISub = s.Sum(x => x.Interest), 
     ASub = s.Sum(x => x.Admin), 
     PSub = s.Sum(x => x.Penalties), 
     TASub = s.Sum(x => x.TotalAmount) 
    }); 
    var GrandTotal = subtotal.Select(s => new 
    { 
     GI = subtotal.Sum(x => x.ISub), 
     GA = subtotal.Sum(x => x.ASub), 
     GP = subtotal.Sum(x => x.PSub), 
     GTA = subtotal.Sum(x => x.TSub) 
    }).Distinct(); 

    //add grand total row to datatable 
    foreach (var a in GrandTotal) 
    { 
     var dr = dt.NewRow(); 
     dr["Category"] = "Grand Total"; 
     dr["Interest"] = a.GI; 
     dr["Admin"] = a.GA; 
     dr["Penalties"] = a.GP; 
     dr["TotalAmount"] = a.GTA; 

     dt.Rows.Add(dr); 

    } 

答えて

2

シングルループでグループ化する実装するとき、これは典型的な間違いです。そのような場合、最後のグループは処理されず、ループの後にコードの重複が必要です。

だからこそ、私は入れ子にされたループアプローチを好みます。キーを取得し、集計を初期化し、キ​​ーが変更されてグループを消費するまで処理します。あなたの特定のケースにそれを適用する

はこのようなものになるだろう:あなたの質問に提供する詳細を使用して

//Get Subtotal 
for (int i = 0; i < dt.Rows.Count; i++) 
{ 
    // Initialize 
    long _CategoryID = Convert.ToInt64(dt.Rows[i]["CategoryID"]); 
    double Admin = 0; double Interest = 0; 
    double Penalties = 0; double TotalAmount = 0; string Title = string.Empty; 
    // Process  
    do 
    { 
     Admin += Convert.ToDouble(dt.Rows[i].IsNull("Admin") ? 0.0 : dt.Rows[i].Field<double>("Admin")); 
     Interest += Convert.ToDouble(dt.Rows[i].IsNull("Interest") ? 0.0 : dt.Rows[i].Field<double>("Interest")); 
     Penalties += Convert.ToDouble(dt.Rows[i].IsNull("Penalties") ? 0.0 : dt.Rows[i].Field<double>("Penalties")); 
     TotalAmount += Convert.ToDouble(dt.Rows[i].IsNull("TotalAmount") ? 0.0 : dt.Rows[i].Field<double>("TotalAmount")); 
     i++; 
    } 
    while (i < dt.Rows.Count && _CategoryID == Convert.ToInt64(dt.Rows[i]["CategoryID"])); 
    // Consume  
    dt.Rows.InsertAt(dt.NewRow(), i); 
    dt.Rows[i]["CategoryID"] = _CategoryID; 
    dt.Rows[i]["Category"] = "Subtotal"; 
    dt.Rows[i]["Admin"] = Admin; 
    dt.Rows[i]["Interest"] = Interest; 
    dt.Rows[i]["Penalties"] = Penalties; 
    dt.Rows[i]["TotalAmount"] = TotalAmount; 
} 
+0

あなたが私を救ったおかげで、この運動は私を殺していました。 –

+0

私はデータベースの万以上のレコードでこの方法を使用しているだけで、それをロードし続けるだけでは停止しません。 –

+0

あなたは上記のコードを意味しますか?パフォーマンスは元のコードと異なるものであってはいけません(これは最後のグループの問題のみを修正しています)。 –

0

、私はLinqPadに次のコードを作成している、それは視覚的にあなたが持っているだけのことを、同じ結果を生成UIに正しく値に収まるようにします。 Linqpad外で別途

  • 小計とGrandtotalを計算CategoryID

  • を使用して、データ処理のためのトランザクションクラス
  • 応用GroupbyDump呼び出しを削除するか、拡張メソッド

    void Main() 
    { 
    var transactions = new List<Transaction> 
    { 
        new Transaction {CategoryID = 1, Category = "Food", Orgname = "Spar", Penalties = 10, Interest = 0, Admin = 15.3,TotalAmount = 20.3}, 
        new Transaction {CategoryID = 1, Category = "Food", Orgname = "Spar", Penalties = 0, Interest = 10, Admin = 20,TotalAmount = 30}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "BMW", Penalties = 0, Interest = 30, Admin = 55,TotalAmount = 85}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "Toyota", Penalties = 9, Interest = 0, Admin = 14.5,TotalAmount = 23.5}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "Jaguar", Penalties = 22.8, Interest = 8.2, Admin = 50,TotalAmount = 81}, 
        new Transaction {CategoryID = 3, Category = "Banking", Orgname = "Absa", Penalties = 0, Interest = 40, Admin = 155,TotalAmount = 190} 
    }; 
    
    var result = transactions.GroupBy(x => x.CategoryID) 
          .Select(y => new 
             { 
              Transactions = y.Select(z => z), 
              SubTotalPenalties = y.Sum(z => z.Penalties), 
              SubTotalInterest = y.Sum(z => z.Interest), 
              SubTotalAdmin = y.Sum(z => z.Admin), 
              SubTotalTotalAmount = y.Sum(z => z.TotalAmount), 
             }); 
    
    result.Dump(); 
    
    double grandTotalPenalties = result.Sum(y => y.SubTotalPenalties); 
    double grandTotalInterest = result.Sum(y => y.SubTotalInterest); 
    double grandTotalAdmin = result.Sum(y => y.SubTotalAdmin); 
    double grandTotalAmount = result.Sum(y => y.SubTotalTotalAmount); 
    
    grandTotalPenalties.Dump(); 
    grandTotalInterest.Dump(); 
    grandTotalAdmin.Dump(); 
    grandTotalAmount.Dump(); 
    } 
    
    public class Transaction 
    { 
    public int CategoryID { get; set;} 
    
    public string Category { get; set;} 
    
    public string Orgname { get; set;} 
    
    public double Penalties { get; set;} 
    
    public double Interest { get; set;} 
    
    public double Admin { get; set;} 
    
    public double TotalAmount { get; set;} 
        } 
    
  • を作成作成した

    +0

    私はデータベースから既存のデータを読んでいます。あなたが私に見せてくれるわけではありません。 –

    +0

    貼り付けたメモリ内のコードを使用して同じ操作を行うことができますが、最初の質問からはあまり明確ではありませんでしたが、 –

    +1

    ご回答いただきありがとうございます。 –

    関連する問題