Linq语法用于查找DataTable中分组行的小计并更新DataTable

时间:2016-03-30 18:38:40

标签: c# linq datatable subtotal linq-group

我一直在讨论这个...我在内存中有一个表,这样的DataTable结构如下:

Input:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   09310   |    123    |    6.0    |    ?
-----------------------------------------------------------------

我希望使用Linq执行以下操作(我对Linq很新!)

对于同一帐户的每一行,将所有付款添加到一起并写入或更新小计字段 我不想折叠表,发票号码会有所不同。我的想法是,有两种方法可以做到这一点

(A)以所有记录的BLANK小计列开头...付款的值将一起添加,然后写入小计列

(B)创建表格时,我将付款值重复到小计字段中。之后,linq只需添加/替换同一列中的值

所以我们会忽略ID和Invoice字段;其帐户和小计(如果使用风格(A)也支付付款)

(A) Input: *(note that there are two records for 123)*
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    
-----------------------------------------------------------------

(B) Input:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    6.0
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    4.0
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    18.0
-----------------------------------------------------------------

Result:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    10.0
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    10.0
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    18.0
-----------------------------------------------------------------

因此,每个小计单元格将拥有每个唯一帐户的所有付款总额

我认为样式(B)会更容易,因为我们只需处理这两列

对于风格(B),我尝试过像

这样的东西
rpTable.AsEnumerable().GroupBy(g => int.Parse(g.Field<string>("Account"))).Select(g => g.Sum(p => p.Field<decimal>("SubTotal")));

但是我可以告诉它遗漏了什么......嗯嗯

3 个答案:

答案 0 :(得分:1)

使用Select,您不会更新表格。这只返回所选值的IEnumerable。

您要做的是将列添加到表中,然后填充它:

var subTotalByAccount = table.AsEnumerable()
            .GroupBy(g => g.Field<string>("Account"))
            .Select(g => new { Account = g.Key, SubTotal = g.Sum(p => p.Field<decimal>("Payment")) })
            .ToDictionary(t => t.Account, t => t.SubTotal);

table.Columns.Add("SubTotal", typeof(decimal));
foreach (var row in table.AsEnumerable())
{
            row.SetField(columnName: "SubTotal", value: subTotalByAccount[row.Field<string>("Account")]);
}

答案 1 :(得分:1)

非常感谢timcbaoth,是的,我同意你说的话。我试图提升您的帖子,但系统说我可能不会:-(
我用暴力来解决(下图),但我也会评估你的解决方案!再次感谢!!

        var query = from row in rpTable.AsEnumerable()
                    group row by int.Parse(row.Field<string>("Account")) into grp
                    orderby grp.Key
                    select new
                    {
                        Id = grp.Key,
                        Sum = grp.Sum(r => r.Field<decimal>("Payment"))
                    };
        foreach (var grp in query)
        {
            rpTable.Select("Account ="+grp.Id).ToList<DataRow>().ForEach(r=>r["Payment"] = grp.Sum);
        }

答案 2 :(得分:-1)

我找到了一个阴险的小虫子,所以我是这样的:

OLD: rpTable.Select("Account ="+grp.Id).ToList<DataRow>().ForEach(r=>r["Payment"] = grp.Sum);   
NEW: rpTable.Select("Account ='"+ grp.Id +"'").ToList<DataRow>().ForEach(r => r["Payment"] = grp.Sum);