Reputation: 439
I have a datatable that looks like this
The output I'm trying to achieve is described in the picture, where I want to group by the month of the datetime, and agent I suppose. This is what I have so far.
DataTable dtTemp = new DataTable();
dtTemp.Columns.Add("Agent", typeof(string));
dtTemp.Columns.Add("Amount", typeof(decimal));
dtTemp.Columns.Add("Date", typeof(DateTime));
dtTemp = dtTemp.AsEnumerable()
.GroupBy(r => r[0])
.Select(g =>
{
var row = dt.NewRow();
row[0] = g.Key;
row[1] = g.Sum(r => (decimal)r[1]);
return row;
})
.CopyToDataTable();
Any ideas how to achieve this?
Upvotes: 3
Views: 1513
Reputation: 71
var temp = dtTemp.AsEnumerable().GroupBy(grp => new {
grpmonth = Convert.ToDateTime(grp["Date"]).Month,
grpyear = Convert.ToDateTime(grp["Date"]).Year,
grpagent = grp["Agent"]
})
.Select(val =>
{
var row = dtTemp.NewRow();
row["Agent"] = val.FirstOrDefault()["Agent"];
row["Amount"] = val.Sum(amt => Convert.ToDecimal(amt["Amount"]));
row["Date"] = val.FirstOrDefault()["Date"];
return row;
})
.CopyToDataTable();
Based on this Stack Overflow answer by Arturo Menchaca.
Upvotes: 0
Reputation: 9771
From analyzing your post, you need to group by data table rows by column Agent
and only month and year from column Date
.
You need to take one temporary data table dt
that can hold data type for each column in your resultant data table result
.
So CopyToDataTable()
will copy all of your dtTemp
group data to new result
data table with temporary dt
columns data type.
DataTable dt = new DataTable();
dt.Columns.Add("Agent", typeof(string));
dt.Columns.Add("Amount", typeof(decimal));
dt.Columns.Add("Date", typeof(string));
DataTable result = dtTemp.AsEnumerable()
.Select(x => new
{
Agent = x.Field<string>("Agent"),
Amount = x.Field<decimal>("Amount"),
Date = x.Field<DateTime>("Date").ToString("MM-yyyy")
})
.GroupBy(x => new { x.Agent, x.Date })
.Select(g =>
{
var r = dt.NewRow();
r["Agent"] = g.Key.Agent;
r["Amount"] = g.Sum(c => c.Amount);
r["Date"] = g.FirstOrDefault().Date;
return r;
})
.CopyToDataTable();
Output:
Upvotes: 2
Reputation: 30454
So from your input sequence, you want all used Agents
, with the total sum of the Amounts
per month.
Let's assume your DataTable is a sequence of Rows, and that it easily can be converted to a sequence of Rows:
class RowData
{
public string Agent {get; set}
public DateTime Date {get; set;}
public int Amount {get; set;}
}
IEnumerable<RowData> tableData = ...
The solution if your problem is to make groups of RowData with equal value for Agent, and to group these groups again to make subgroups with equal value for year and month
var AgentsWithAmountsPerMonth = tableData
.GroupBy(row => row.Agent, // make groups of rows with same Agent
// ResultSelector: get the Agent (=key), with all rows that have this Agent
(agent, rowsWithThisAgent) => new
{
Agent = agent,
// to calculate the totals per year/month, extract the year / month / amount
TotalsPerMonth = rowsWithThisAgent.Select(row => new
{
Year = row.Date.Year,
Month = row.Date.Month,
Amount = row.Amount,
})
// and group by same Year / Month:
.GroupBy(row => new {row.Year, row.Month},
// ResultSelector
(yearMonth, rowsWithThisYearMonth) => new
{
Year = yearMonth.Year,
Month = yearMonth.Month,
Total = rowsWithThisYearMont.Select(row => row.Amount).Sum(),
// Or put the year and month in one field:
Month = new DateTime(yearMonth.Year, yearMonth.Month, 1),
},
});
});
Upvotes: 0