简体   繁体   中英

Sum columns in datatable based on values from another column

I have a database table that I am using as a source for a report. The table layout looks like. Table 1 is subset of a larger database table. But for the report I only need certain columns So I am creating a new data table by using the function given below

Value  Description   Hours
    1          A           2
    2          B           3
    3          C           5
    1          A           3
    2          B           4
    2          B           3
    3          C           3


private DataTable CreateFocusOfEffortData()
    {
        var dtChartData = new DataTable();
        dtChartData.Columns.Add("Description", typeof(string));
        dtChartData.Columns.Add("Hours", typeof(Double));
        var myDataView = ReportData.DefaultView;
        myDataView.RowFilter = "ActivityUnitID = " + _ActivityUnitID;
        for (var i = 0; i < myDataView.ToTable().Rows.Count; i++)
        {
            var dataRow = new Object[dtChartData.Columns.Count];
            dataRow[0] = ReportData.Rows[i]["Description"];
            dataRow[1] = csaConvert.ToDouble(ReportData.Rows[i]["Hours"]);
            dataRow[2] = ReportData.Rows[i]["Value"];
            dtChartData.Rows.Add(dataRow);
        }
        return dtChartData;
    }

Now I need to design another report with summary data from above table. This table should combine data for all the columns based on Column["Value]. for example in my case we have three distinct values in Value column 1,2,3. The resulting table should have hours summed up for all the three values.

    Value   Description  Hours
    1         A           5
    2         B           10
    3         C           8

Now I can do this in sql by creating another stored proc but I would rather use my existing data-table and write a C# function to get the result. Is there a easier way to achieve this using LINQ?

You are taking the wrong approach. Do this work in SQL.

 SELECT value, description, sum(hours) as hours from tblData group by value, description;

The above will give you the second table you show in your question.

The reason to do it this way is that passing data to a client application just to have it passed right back to SQL consumes memory and system calls unnecessarily. Also, there is much less room for error, bugs, type conversion issues, etc.

If you really want to make the narrower table (which is generally a bad idea), do it like this:

 SELECT value, description, hours from tblData into tblSkinnyData;

In general, if you needed this skinny table for some reason, you would use a VIEW on the main table.

You can use AsEnumerable() in order to use LINQ, then GroupBy by Value and Description and do Sum on Hours to set for the first row:

var result = dtChartData.AsEnumerable()
            .GroupBy(row => new
                {
                    Value = row.Field<int>("Value"),
                    Description = row.Field<string>("Description")
                })
            .Select(g =>
                {
                    var row = g.First();
                    row.SetField("Hours", g.Sum(r => r.Field<double>("Hours")));

                    return row;
                });

The result will return IEnumerable<DataRow> but if you want to get DataTable back, use:

var resultTable = result.CopyToDataTable();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM