Dynamic PIVOT using C# Linq - linq

I am trying to use following code to create the PIVOT but its not working.
It's giving me compile time error. I don't know linq so unable to use it.
Please help :
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast(<DataColumn>)
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast(<DataColumn>).ToArray();
dt.AsEnumerable()
.Select(r =>; r[pivotColumn.ColumnName].ToString())
.Distinct().ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
}
return result;
}
Code from : http://michaeljswart.com/2011/06/forget-about-pivot/
Moreover it tried to use following code, it works well except for it is not giving total sum for Value Column
public DataTable GetInversedDataTable(DataTable table, string columnX, string columnY, string columnZ, string nullValue, bool sumValues)
{
//Create a DataTable to Return
DataTable returnTable = new DataTable();
DataTable tempTable = table.Clone();
if (string.IsNullOrEmpty(columnX))
{
columnX = table.Columns[0].ColumnName;
}
tempTable.Columns.Remove(columnX);
//Add a Column at the beginning of the table
//returnTable.Columns.Add(columnY);
returnTable = tempTable.Clone();
//Read all DISTINCT values from columnX Column in the provided DataTale
List<string> columnXValues = new List<string>();
foreach (DataRow dr in table.Rows)
{
string columnXTemp = dr[columnX].ToString();
if (!columnXValues.Contains(columnXTemp))
{
//Read each row value, if it's different from others provided, add to the list of values and creates a new Column with its value.
columnXValues.Add(columnXTemp);
returnTable.Columns.Add(columnXTemp);
}
}
//Verify if Y and Z Axis columns re provided
if (!string.IsNullOrEmpty(columnY) && !string.IsNullOrEmpty(columnZ))
{
//Read DISTINCT Values for Y Axis Column
List<string> columnYValues = new List<string>();
foreach (DataRow dr in table.Rows)
{
if (!columnYValues.Contains(dr[columnY].ToString()))
{
columnYValues.Add(dr[columnY].ToString());
}
}
//Loop all Column Y Distinct Value
foreach (string columnYValue in columnYValues)
{
//Creates a new Row
DataRow drReturn = returnTable.NewRow();
drReturn[0] = columnYValue;
//foreach column Y value, The rows are selected distincted
DataRow[] rows = table.Select((columnY + "='") + columnYValue + "'");
//Read each row to fill the DataTable
foreach (DataRow dr in rows)
{
string rowColumnTitle = dr[columnX].ToString();
//Read each column to fill the DataTable
foreach (DataColumn dc in returnTable.Columns)
{
if (dc.ColumnName == rowColumnTitle)
{
//If Sum of Values is True it try to perform a Sum
//If sum is not possible due to value types, the value displayed is the last one read
if (sumValues)
{
try
{
drReturn[rowColumnTitle] = Convert.ToDecimal(drReturn[rowColumnTitle]) + Convert.ToDecimal(dr[columnZ]);
}
catch
{
drReturn[rowColumnTitle] = dr[columnZ];
}
}
else
{
drReturn[rowColumnTitle] = dr[columnZ];
}
}
}
}
returnTable.Rows.Add(drReturn);
}
}
else
{
throw new Exception("The columns to perform inversion are not provided");
}
//if a nullValue is provided, fill the datable with it
if (!string.IsNullOrEmpty(nullValue))
{
foreach (DataRow dr in returnTable.Rows)
{
foreach (DataColumn dc in returnTable.Columns)
{
if (string.IsNullOrEmpty(dr[dc.ColumnName].ToString()))
{
dr[dc.ColumnName] = nullValue;
}
}
}
}
return returnTable;
}
GetInversedDataTable(dtNormal, "Dated", "OrderStatus", "Qty", " ", true);
Please help :)

Here is the code with the compilation errors corrected:
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
dt.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct().ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
}
return result;
}
I changed Cast(<DataColumn>) to Cast<DataColumn>() in two locations and got rid of the semicolon in the middle of a lambda expression. The second part of your question is a little trickier. You may want to ask it as its own question.

Good one., but you might want to replace the below line
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
with this (change pivotColumn to pivotValue)
.ForEach (c => result.Columns.Add(c, pivotValue.DataType));
Works perfectly for my requirement.

Related

Dynamic LINQ Where query with joining other tables

I have several tables (the exact number is not known when the program is build) looking like this (the number of rows and columns may differ from table to table):
The source data is stored in a data set. Now I want to generate a new table where all data of all ids is stored (the picture shows only the result for id 10 and 20 but the target table should contain the data for all ids):
The equivalent SQLite statement for that looks like this:
SELECT * FROM Dataset
JOIN Datensatz2 ON (Dataset.ID=Datensatz2.ID)
JOIN Datensatz3 ON (Datensatz3.ID=Dataset.ID)
JOIN Datensatz4 ON (Datensatz4.ID=Dataset.ID)
WHERE Dataset.Id=10
UNION
SELECT * FROM Dataset
JOIN Datensatz2 ON (Dataset.ID=Datensatz2.ID)
JOIN Datensatz3 ON (Datensatz3.ID=Dataset.ID)
JOIN Datensatz4 ON (Datensatz4.ID=Dataset.ID)
WHERE Dataset.Id=20
...
The double id columns will be removed afterwards so donĀ“t worry about that. The questions is now how to convert it as a dynamic LINQ query?
There are plenty of open question but maybe this helps to solve it. Since the tables are already stored in a DataSet you could use Linq-To-DataSet and Enumerable.GroupBy to group by ID:
var idTables = ds.Tables.Cast<DataTable>().Where(t => t.Columns.Contains("Id"));
if(!idTables.Any()){ MessageBox.Show("No id-tables"); return; }
var idRowGroups = idTables.SelectMany(t => t.AsEnumerable())
.GroupBy(row => row.Field<int>("Id"))
.Select(grp => new { ID = grp.Key, Rows = grp });
foreach(var idGroup in idRowGroups)
{
Console.WriteLine("ID:{0} Rows:{1}"
, idGroup.ID
, String.Join(" | ", idGroup.Rows.Select(row => String.Join(",", row.ItemArray))));
}
Sample data:
var ds = new DataSet();
DataTable t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data", typeof(int));
t1.Rows.Add(1, 1);
t1.Rows.Add(2, 10);
t1.Rows.Add(3, 100);
t1.Rows.Add(4, 1000);
ds.Tables.Add(t1);
t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data", typeof(int));
t1.Rows.Add(4, 5);
t1.Rows.Add(5, 50);
t1.Rows.Add(7, 500);
t1.Rows.Add(3, 5997);
ds.Tables.Add(t1);
t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data1", typeof(int));
t1.Columns.Add("Data2", typeof(int));
t1.Rows.Add(1, 5, 0);
t1.Rows.Add(3, 7, 1);
t1.Rows.Add(5, 9, 11);
t1.Rows.Add(7, 11, 222);
ds.Tables.Add(t1);
Output:
ID:1 Rows:1,1 | 1,5,0
ID:2 Rows:2,10
ID:3 Rows:3,100 | 3,5997 | 3,7,1
ID:4 Rows:4,1000 | 4,5
ID:5 Rows:5,50 | 5,9,11
ID:7 Rows:7,500 | 7,11,222
Ok, I finally made it but it seems to be much too complicated. If someone is able to help me improve the solution he is very welcome.
DataSet dsResult = new DataSet();
var idTables = ds.Tables.Cast<DataTable>().Where(t => t.Columns.Contains("ID"));
if (!idTables.Any()) { MessageBox.Show("No id-tables"); return; }
var idRowGroups = idTables.SelectMany(t => t.AsEnumerable())
.GroupBy(row => row.Field<Int64>("ID"))
.Select(grp => new { ID = grp.Key, Rows = grp });
foreach (var idGroup in idRowGroups)
{
var liste = idGroup.Rows.ToList();
for (int i = 0; i < liste.Count; i++)
{
if (!dsResult.Tables.Contains(liste[i].Table.TableName))
{
dsResult.Tables.Add(liste[i].Table.TableName);
foreach (DataColumn dtCol in liste[i].Table.Columns)
{
if (dsResult.Tables[liste[i].Table.TableName].Columns.Contains("ID"))
dsResult.Tables[liste[i].Table.TableName].Columns.Add(dtCol.ColumnName+i.ToString());
else
{
dsResult.Tables[liste[i].Table.TableName].Columns.Add(dtCol.ColumnName);
}
dsResult.Tables[liste[i].Table.TableName].Columns[dtCol.ColumnName].DataType = dtCol.DataType;
}
}
DataRow dRow = dsResult.Tables[liste[i].Table.TableName].NewRow();
dRow.ItemArray = liste[i].ItemArray;
dsResult.Tables[liste[i].Table.TableName].Rows.Add(dRow);
}
IEnumerable<IEnumerable<DataRow>> allTablesRows = dsResult.Tables.Cast<DataTable>()
.Select(table => table.AsEnumerable())
.CartesianProduct();
int k = 0;
foreach (var rows in allTablesRows)
{
DataRow zRow = dsErgebnis.Tables[2].NewRow();
foreach (DataRow dRow in rows)
{
for (int i = 0; i < dRow.ItemArray.Length; i++)
{
zRow[k] = dRow.ItemArray[i];
k++;
}
}
k = 0;
dsErgebnis.Tables[2].Rows.Add(zRow);
}
dsResult.Clear();
}
First I filter the content by ID.
Then I put the result in a new tables (all rows with the ID 10 I found in 'Datasatz2' in dataset 'ds' for example I put to a new table 'Datasatz2' in the dataset 'dsResult').
At least I build the cartesian product of all tables and store it in dtaset dsErgebnis.
The result is what I expect but as mentioned before I am not satisfied with the solution.

Adding Sum per row in PIVOT using LINQ

I have following function that converts normal DataTable to Pivot Table.
But I have 1 more requirement, it should also show Value column i.e sum of all the Pivot column cell.
e.g. : ORDER | SUM | PLANDATE
1 50 10-Oct-2012
1 10 10-Oct-2012
2 15 12-Oct-2012
After PIVOT it should be like
ORDER | SUM | 10-Oct-2012 | 12-Oct-2012
1 60 50 10
2 15 15
my pivot function is :
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
dt.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct().ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
}
return result;
}
Thanks & any help will be appriciated...
Sample Data :
OrderStatus Qty Dated
New 100 10-Oct-2012
New 150 10-Oct-2012
New 100 10-Oct-2012
Conf 200 12-Oct-2012
New 100 12-Oct-2012
Reconf 300 12-Oct-2012
New 200 15-Oct-2012
New 200 15-Oct-2012
Reconf 100 18-Oct-2012
New 150 18-Oct-2012
Conf 150 18-Oct-2012
New 100 20-Oct-2012
Reconf 500 20-Oct-2012
New 100 30-Oct-2012
New 700 30-Oct-2012
New 100 30-Oct-2012
Conf 100 10-Oct-2012
Update Code :
private DataTable DataTableToPivot(DataTable dtNormalTable, DataColumn pivotColumn, DataColumn valueColumn)
{
cTracing.WriteTrace("Inside DataTableToPivot", "DataTableToPivot");
DataTable dtPivot = null;
DataTable tempPivot = null;
DataColumn sumColumn = new DataColumn();
string[] pkColumnNames = null;
try
{
sumColumn.ColumnName = valueColumn.ColumnName;
sumColumn.DataType = typeof(string);
sumColumn.DefaultValue = "0";
var allrows = dt.AsEnumerable().Select(delegate(DataRow r)
{
DataRow nr = dt.NewRow();
foreach (DataColumn item in dt.Columns)
{
nr.SetField(item.ColumnName, r[item.ColumnName] is DBNull ? string.Empty : r[item.ColumnName]);
}
return nr;
});
dtNormalTable = allrows.CopyToDataTable();
// find primary key columns
//(i.e. everything but pivot column and pivot value)
tempPivot = dtNormalTable.Copy();
tempPivot.Columns.Remove(pivotColumn.ColumnName);
tempPivot.Columns.Remove(valueColumn.ColumnName);
pkColumnNames = tempPivot.Columns
.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToArray();
// prep results table
dtPivot = tempPivot.DefaultView.ToTable(true, pkColumnNames).Copy();
dtPivot.PrimaryKey = dtPivot.Columns.Cast<DataColumn>().ToArray();
// include the sum column
dtPivot.Columns.Add(sumColumn);
try
{
dtNormalTable.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct()
.ToList()
.ForEach(c => dtPivot.Columns.Add(Convert.ToDateTime(c).ToString("dd-MMM-yyyy"), typeof(string)));
}
catch
{
dtNormalTable.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct()
.ToList()
.ForEach(c => dtPivot.Columns.Add(c, typeof(string)));
}
// load it
foreach (DataRow row in dtNormalTable.Rows)
{
// find row to update
DataRow aggRow = dtPivot.Rows.Find(
pkColumnNames
.Select(c => row[c])
.ToArray());
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
string columnName = string.Empty;
try
{
columnName = Convert.ToDateTime(row[pivotColumn.ColumnName]).ToString("dd-MMM-yyyy");
}
catch
{
columnName = row[pivotColumn.ColumnName].ToString();
}
if (aggRow.IsNull(columnName))
{
aggRow[columnName] = Convert.ToDecimal(row[valueColumn.ColumnName]);
}
else
{
aggRow[columnName] = Convert.ToDecimal(aggRow[columnName]) +
Convert.ToDecimal(row[valueColumn.ColumnName]);
}
if (numberFormat == "3")
{
// add the value to the sum
aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.000");
}
else if (numberFormat == "2")
{
// add the value to the sum
aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.00");
}
else if (numberFormat == "1")
{
// add the value to the sum
aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.0");
}
else
{
// add the value to the sum
aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0");
}
}
return dtPivot;
}
catch (Exception ex)
{
cTracing.WriteTrace("Error inside DataTableToPivot", "DataTableToPivot");
cLogging.WriteLog(ex);
return null;
}
finally
{
if (dtPivot != null)
dtPivot.Dispose();
}
}
enter code here
How about adding each row's value to the sum column in the corresponding aggregate row?
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
DataColumn sumColumn = new DataColumn();
sumColumn.ColumnName = "SUM";
sumColumn.DataType = typeof(int);
sumColumn.DefaultValue = 0;
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
// include the sum column
result.Columns.Add(sumColumn);
dt.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct()
.OrderBy(c => Convert.ToDateTime(c)) // Order by the date
.ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
string columnName = row[pivotColumn.ColumnName].ToString();
if(aggRow.IsNull(columnName))
{
aggRow[columnName] = (int)row[pivotValue.ColumnName];
}
else
{
aggRow[columnName] = Convert.ToInt32(aggRow[columnName]) +
(int)row[pivotValue.ColumnName];
}
// add the value to the sum
aggRow[sumColumn] = (int)aggRow[sumColumn] +
(int)row[pivotValue.ColumnName];
}
return result;
}

linq query for update more than one record

I have a table named industries. In this my fields are
workfor_id,
workfor_usr_id,
workfor_industry_id.
With the same values of workfor_id, I have different workfor_industry_id's.
foreach (var k in us){
var ind = dbContext.industries.Where(i => i.workfor_id ==
k.id).Select(i => i).FirstOrDefault();
string ind2 = k.industry;
var industryParts = ind2.Split(',');
var o = (industryParts.Length);
for (c = 0; c < o; c++){
ind.workfor_id = Convert.ToInt16(k.id);
ind.workfor_industry_id = Convert.ToInt16(k.industryid); }
}
To update workfor_industry_id field I have implemented inner loop inside the foreach loop to get the values of workfor_industry_id's.here same record is over loading with different workfor_industry_id's.
can you tell me how to implement this.
UPDATED
This update adds a little more error checking and assumes that -1 is never a valid value for industry_id
short GetShort(string value) {
short returnValue;
value = (value ?? string.Empty).Replace("\"",null);
return short.TryParse(value, out returnValue) ? returnValue : (short)-1;
}
foreach (var k in us){
var id=Convert.ToInt16(k.id);
var toRemove=from i in dbContext.industries
where i.workfor_id == k.id
select i;
var toAdd = from x in (k.industry ?? string.Empty).Split(',')
select new Industry {
workfor_id=id,
workfor_industry_id=GetShort(x)
};
dbContext.industries.DeleteAllOnSubmit(toRemove);
dbContext.industries.InsertAllOnSubmit(toAdd.Where(x=>x.workfor_industry_id != -1));
}
dbContext.SubmitChanges();

DataTable that has List<string> in it

I'm using Linq to return data from an XML file to a DataTable and that works. But now I'm trying to modify the code to loop through the DataTable. I created a custom class to model the data and have a List in my model. When I loop through the DataTable to display records it displays System.Collections.Generic.List`1[System.String] instead of the actual data. I'm not sure what to search to find the answer.
Snippet:
foreach (DataRow row in tbl.Rows)
{
myList = row["myList"] + ", " + myList;
}
The myList column is the List. I hope this makes sense.
Edited:
public static DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ?DBNull.Value :pi.GetValue
(rec,null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
hobbiesList = (List<string>)row["hobbies"];
foreach (var item in hobbiesList)
{
hobbies.Add(item.ToString());
}
hobby = string.Join(", ", hobbies.ToArray());
hobbies.Clear();
I had to do the above to get it to work. I then add hobby to my output array.

DataTable linq query iteration

I want to Enumerate Linq Query. Below i specified example.
EX:
DataTable _slidingDataTable = new DataTable("test");
for(int i=0; i<5;i++)
{
DataRow row = _slidingDataTable.NewRow();
startPosition = DateTime.Now;
for(int i=0; i<5;i++)
{
_slidingDataTable.Columns.Add("TransferTime");
row[columnName] = startPosition ;
_slidingDataTable.Columns.Add("TransferData");
row[columnName] = "Test"+i;
}
_slidingDataTable.Rows.Add(row);
}
var query1 = from myRow in _slidingDataTable.AsEnumerable()
where myRow.Field<DateTime>("TransferTime") == startPosition
select myRow;
This query output should be collection of rows. How to get collection row & iterate.
In your context, query1 is an EnumerableRowCollection<DataRow> because you used _slidingDataTable.AsEnumerable(), and you can iterate over it like so :
foreach (DataRow row in query1)
{
// Do stuff with that row
}
I'm giving you an example by which you can see it and it also includes sum in groupby.
var drdatedisp = from row in dtfullreport.AsEnumerable()
group row by row.Field<string>("Order_Date") into g
select new
{
Order_Date = g.Key,
totalQnty = g.Sum(a => a.Field<int>("Item_Quantity")),
totalTax = g.Sum(a => float.Parse(a.Field<decimal>("TAXAMT").ToString())),
totalAmt = g.Sum(a => float.Parse(a.Field<decimal>("VALAMT").ToString()))
};
DataTable dtdatedisp = new DataTable();
dtdatedisp.Columns.Add("Order_Date");
dtdatedisp.Columns.Add("Item_Quantity");
dtdatedisp.Columns.Add("TAXAMT");
dtdatedisp.Columns.Add("VALAMT");
dtdatedisp.Rows.Clear();
foreach (var g in drdatedisp)
{
DataRow newRow1 = dtdatedisp.NewRow();
newRow1[0] = g.Order_Date;
newRow1[1] = g.totalQnty;
newRow1[2] = String.Format("{0:0.00}", g.totalTax);
newRow1[3] = String.Format("{0:0.00}", g.totalAmt);
dtdatedisp.Rows.Add(newRow1);
}

Resources