Goal
A few days ago a reader asked for Multiple column group by on DataTable. This blos is in reply of that question. This was my old blog Apply group by clause on Datatable in C#.Solution
#region System using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; #endregion namespace SampleApplication { #region Enums /// <summary> /// The functions which can be used for aggreation /// </summary> public enum AggregateFunction { Sum, Avg, Count, Max, Min } #endregion #region Entity /// <summary> /// The class which will have properties of function to be performed and on which field /// </summary> public class DataTableAggregateFunction { /// <summary> /// The function to be performed /// </summary> public AggregateFunction enmFunction { get; set; } /// <summary> /// Performed for which column /// </summary> public string ColumnName { get; set; } /// <summary> /// What should be the name after output /// </summary> public string OutPutColumnName { get; set; } } #endregion public class Helper { /// <summary> /// Demo for Group By /// </summary> public void DemoGroupBy() { //Gets the mock data table DataTable _dt = GetDataTable(); //Add columns which you want to group by IList<string> _groupByColumnNames = new List<string>(); _groupByColumnNames.Add("State"); _groupByColumnNames.Add("City"); //Functions you want to perform on which fields IList<DataTableAggregateFunction> _fieldsForCalculation = new List<DataTableAggregateFunction>(); _fieldsForCalculation.Add(new DataTableAggregateFunction() { enmFunction = AggregateFunction.Avg, ColumnName = "Population", OutPutColumnName = "PopulationAvg" }); _fieldsForCalculation.Add(new DataTableAggregateFunction() { enmFunction = AggregateFunction.Sum, ColumnName = "Population", OutPutColumnName = "PopulationSum" }); _fieldsForCalculation.Add(new DataTableAggregateFunction() { enmFunction = AggregateFunction.Count, ColumnName = "Population", OutPutColumnName = "PopulationCount" }); _fieldsForCalculation.Add(new DataTableAggregateFunction() { enmFunction = AggregateFunction.Max, ColumnName = "Year", OutPutColumnName = "YearMax" }); _fieldsForCalculation.Add(new DataTableAggregateFunction() { enmFunction = AggregateFunction.Min, ColumnName = "Year", OutPutColumnName = "YearMin" }); //Gets the result after grouping by DataTable dtGroupedBy = GetGroupedBy(_dt, _groupByColumnNames, _fieldsForCalculation); } /// <summary> /// Returns a mock data table /// </summary> /// <returns></returns> private DataTable GetDataTable() { //Declarations DataTable _dt = new DataTable(); DataRow _dr; //Create columns _dt.Columns.Add(new DataColumn() { ColumnName = "State" }); _dt.Columns.Add(new DataColumn() { ColumnName = "City" }); _dt.Columns.Add(new DataColumn() { ColumnName = "Year", DataType = typeof(System.Int32) }); _dt.Columns.Add(new DataColumn() { ColumnName = "Population", DataType = typeof(System.Int32) }); //Add mock data _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Ahmedabad"; _dr["Year"] = 2009; _dr["Population"] = 6000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Surat"; _dr["Year"] = 2009; _dr["Population"] = 2000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Rajkot"; _dr["Year"] = 2009; _dr["Population"] = 1000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Maharastra"; _dr["City"] = "Mumbai"; _dr["Year"] = 2009; _dr["Population"] = 3000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Maharastra"; _dr["City"] = "Pune"; _dr["Year"] = 2009; _dr["Population"] = 3000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Ahmedabad"; _dr["Year"] = 2010; _dr["Population"] = 8000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Maharastra"; _dr["City"] = "Mumbai"; _dr["Year"] = 2010; _dr["Population"] = 8000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Ahmedabad"; _dr["Year"] = 2011; _dr["Population"] = 6000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Surat"; _dr["Year"] = 2011; _dr["Population"] = 2000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Gujarat"; _dr["City"] = "Rajkot"; _dr["Year"] = 2011; _dr["Population"] = 1000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Maharastra"; _dr["City"] = "Mumbai"; _dr["Year"] = 2011; _dr["Population"] = 3000000; _dt.Rows.Add(_dr); _dr = _dt.NewRow(); _dr["State"] = "Maharastra"; _dr["City"] = "Pune"; _dr["Year"] = 2011; _dr["Population"] = 3000000; _dt.Rows.Add(_dr); //Return table return _dt; } /// <summary> /// Group by DataTable /// </summary> /// <param name="_dtSource"></param> /// <param name="_groupByColumnNames"></param> /// <param name="_fieldsForCalculation"></param> /// <returns></returns> private DataTable GetGroupedBy(DataTable _dtSource, IList<string> _groupByColumnNames, IList<DataTableAggregateFunction> _fieldsForCalculation) { //Once the columns are added find the distinct rows and group it bu the numbet DataTable _dtReturn = _dtSource.DefaultView.ToTable(true, _groupByColumnNames.ToArray()); //The column names in data table foreach (DataTableAggregateFunction _calculatedField in _fieldsForCalculation) { _dtReturn.Columns.Add(_calculatedField.OutPutColumnName); } //Gets the collection and send it back for (int i = 0; i < _dtReturn.Rows.Count; i = i + 1) { #region Gets the filter string string _filterString = string.Empty; for (int j = 0; j < _groupByColumnNames.Count; j = j + 1) { if (j > 0) { _filterString += " AND "; } if (_dtReturn.Columns[_groupByColumnNames[j]].DataType == typeof(System.Int32)) { _filterString += _groupByColumnNames[j] + " = " + _dtReturn.Rows[i][_groupByColumnNames[j]].ToString() + ""; } else { _filterString += _groupByColumnNames[j] + " = '" + _dtReturn.Rows[i][_groupByColumnNames[j]].ToString() + "'"; } } #endregion #region Compute the aggregate command foreach (DataTableAggregateFunction _calculatedField in _fieldsForCalculation) { _dtReturn.Rows[i][_calculatedField.OutPutColumnName] = _dtSource.Compute(_calculatedField.enmFunction.ToString() + "(" + _calculatedField.ColumnName + ")", _filterString); } #endregion } return _dtReturn; } } }
How to Use?
Call the function from somewhere.
(new SampleApplication.Helper()).DemoGroupBy();
Screenshot
Before Group By : After Group By :Please let me know if this helped.