在一个记录中合并DataTable中的重复行并更新一些列

时间:2018-03-22 08:11:57

标签: c#

我的C#代码中有Datatable

DataTable dtDetails;

我的数据表如何跟踪记录;

id | tid | code | pNameLocal        | qty | price
-------------------------------------------------
1  |101  | 101  | some_local_name   | 2   |20.36
2  |102  | 202  | some_local_name   | 1   |15.30 // exactly same entry 
3  |102  | 202  | some_local_name   | 1   |15.30 // exactly same entry
4  |102  | 202  | some_local_name   | 1   |10.00 //same entry as same tid but price is different
5  |102  | 202  | some_local_name   | 2   |15.30 //same entry as same tid but different qty
6  |102  | 202  | some_local_name2  | 1   |15.30 //same entry as same tid but pNameLocal different
7  |103  | 202  | some_local_name   | 1   |15.30 // different entry of same product see different tid
8  |104  | 65   | some_local_name   | 5   |05.00
9  |105  | 700  | some_local_name   | 2   |07.01 // does not exist in "dtProduct"

要做的是完全相同但多次输入以合并为一个的记录,但保持其qty列和price列更新,例如在上面DaraRows < strong> id 2和3与id 1 具有完全相同的记录,这应该是一条记录,并通过添加完全相同的重复记录来更新qtyprice。这应该在同一DataTable或新版本中更新。

4 个答案:

答案 0 :(得分:1)

您可以将DataTable视为可以使用,并使用Linq创建新的DataTable。代码看起来像这样:

    DataTable newDt = dt.AsEnumerable()
        .GroupBy(r => r.Field<int>("tid"))
        .Select(g => {
            var row = dt.NewRow();

            row["tid"] = g.Key;
            row["code"] = g.First(r => r["code"] != null).Field<int>("code");
            row["pNameLocal"] = g.First(r => r["pNameLocal"] != null).Field<string>("pNameLocal");
            row["qty"] = g.Sum(r => r.Field<int>("qty"));
            row["price"] = g.Sum(r => r.Field<double>("price"));

            return row;
        }).CopyToDataTable();

请参阅下面的示例控制台应用程序,设置示例数据,执行分组以及显示原始数据和结果数据表。

using System;
using System.Data;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
    static void Main(string[] args)
    {
        var dt = FillUpTestTable();
        DumpDataTable(dt);
        DataTable newDt = dt.AsEnumerable()
            .GroupBy(r => r.Field<int>("tid"))
            .Select(g => {
                var row = dt.NewRow();

                row["tid"] = g.Key;
                row["code"] = g.First(r => r["code"] != null).Field<int>("code");
                row["pNameLocal"] = g.First(r => r["pNameLocal"] != null).Field<string>("pNameLocal");
                row["qty"] = g.Sum(r => r.Field<int>("qty"));
                row["price"] = g.Sum(r => r.Field<double>("price"));

                return row;
            }).CopyToDataTable();

        Console.WriteLine();
        Console.WriteLine("Result: ");
        Console.WriteLine();

        DumpDataTable(newDt);
        Console.ReadLine();
    }

    private static DataTable FillUpTestTable()
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("id", typeof(int));
        dt.Columns.Add("tid", typeof(int));
        dt.Columns.Add("code", typeof(int));
        dt.Columns.Add("pNameLocal", typeof(string));
        dt.Columns.Add("qty", typeof(int));
        dt.Columns.Add("price", typeof(double));

        dt.Rows.Add(1, 101, 101, "some_local_name", 2, 20.36);
        dt.Rows.Add(2, 102, 202, "some_local_name", 2, 15.30);
        dt.Rows.Add(3, 102, 202, "some_local_name", 2, 15.30);
        dt.Rows.Add(4, 102, 202, "some_local_name", 2, 10.00);
        dt.Rows.Add(5, 102, 202, "some_local_name", 2, 15.30);
        dt.Rows.Add(6, 102, 202, "some_local_name2", 1, 15.30);
        dt.Rows.Add(7, 103, 202, "some_local_name", 2, 15.30);
        dt.Rows.Add(8, 104, 202, "some_local_name", 2, 05.00);
        dt.Rows.Add(9, 105, 202, "some_local_name", 2, 07.01);

        return dt;
    }
    private static void DumpDataTable(DataTable newDt)
    {
        foreach (DataRow dataRow in newDt.Rows)
        {
            foreach (var item in dataRow.ItemArray)
            {
                Console.Write(item + "   | ");
            }
            Console.WriteLine();
        }
    }
}

}

答案 1 :(得分:1)

你需要在datatable中使用这个:

SELECT tid, code, pNameLocal, sum(qty),sum(price) FROM @tbl
group by tid, code, pNameLocal,qty, price

你可以使用linq。请尝试以下代码。我试图使用你的样本记录。

 DataTable dt = new DataTable();

            DataColumn[] dcCol =  {
                new DataColumn("id",typeof(int)),
                new DataColumn("tid", typeof(int)),
                new DataColumn("code", typeof(int)),
                new DataColumn("pNameLocal", typeof(string)),
                new DataColumn("qty", typeof(int)),
                new DataColumn("price", typeof(decimal))
        };

            dt.Columns.AddRange(dcCol);


            dt.Rows.Add(1, 101, 101, "some_local_name", 2, 20.36);
            dt.Rows.Add(2, 102, 202, "some_local_name", 1, 10.00);
            dt.Rows.Add(3, 102, 202, "some_local_name", 1, 15.30);
            dt.Rows.Add(4, 102, 202, "some_local_name", 1, 10.00);
            dt.Rows.Add(5, 102, 202, "some_local_name", 2, 15.30);
            dt.Rows.Add(6, 102, 202, "some_local_name2", 1, 15.30);
            dt.Rows.Add(7, 103, 202, "some_local_name", 1, 15.30);
            dt.Rows.Add(8, 104, 65, "some_local_name", 5, 05.00);
            dt.Rows.Add(9, 105, 700, "some_local_name", 2, 07.01);


            var dtnew = from r in dt.AsEnumerable()
                        group r by new
                        {
                            tid = r.Field<int>("tid"),
                            code = r.Field<int>("code"),
                            pNameLocal = r.Field<string>("pNameLocal"),
                            qty = r.Field<int>("qty"),
                            price = r.Field<decimal>("price")
                        } into grp
                        select new
                        {
                            tid1 = grp.Key.tid,
                            code1 = grp.Key.code,
                            pNameLocal1 = grp.Key.pNameLocal,
                            SumQty = grp.Sum(r => grp.Key.qty),
                            sumPrice = grp.Sum(r => grp.Key.price)
                        };

答案 2 :(得分:1)

您可以对包含除计数和价格之外的所有列的匿名类型使用GroupBy

var aggregatedRowData = dtDetails.AsEnumerable()
    .Select(r => new
    {
        tid = r.Field<int>("tid"),
        code = r.Field<int>("code"),
        pNameLocal = r.Field<string>("pNameLocal"),
        qty = r.Field<int>("qty"),
        price = r.Field<decimal>("price"),
    })
    .GroupBy(x => new { x.tid, x.code, x.pNameLocal })
    .Select(grp => new
    {
        grp.Key.tid,
        grp.Key.code,
        grp.Key.pNameLocal,
        qty = grp.Sum(x => x.qty),
        price = grp.Sum(x => x.price)
    });

DataTable aggregatedTable = dtDetails.Clone();  // empty, same columns
foreach (var x in aggregatedRowData)
    aggregatedTable.Rows.Add(x.tid, x.code, x.pNameLocal, x.qty, x.price);

答案 3 :(得分:0)

这是你可以做的如果要基于所有列来区分行。

DataTable newDatatable = dt.DefaultView.ToTable(true, "tid", "code", "pNameLocal", "qty", "price");

您在此处提到的列,只有那些将在newDatatable中返回。