I have a DataSet with 2 DataTable's. Each DataTable contains a column called "cost".
I want to calculate the sum of all costs for the 2 tables in a table called Result table, like the example below. How can I do that?
Table 1
Name | cost
balan | 6
gt | 5
Table 2
Name | cost
balan | 2
gt | 8
Result table
Name | cost
balan | 8
gt | 12
This is a way to do it:
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
DataTable results = new DataTable();
dt1.Columns.Add("Name");
dt1.Columns.Add("cost", typeof(int));
dt2.Columns.Add("Name");
dt2.Columns.Add("cost", typeof(int));
results.Columns.Add("Name");
results.Columns.Add("cost", typeof(int));
dt1.Rows.Add("balan", 6);
dt2.Rows.Add("balan", 2);
dt1.Rows.Add("gt", 5);
dt2.Rows.Add("gt", 8);
foreach (DataRow dr1 in dt1.Rows)
{
results.Rows
.Add(
dr1["Name"],
(int)dr1["cost"] + (int)dt2.Select(String.Format("Name='{0}'", dr1["name"]))[0]["cost"]
);
}
to get the result, you can do something like
var table1 = yourDataSet.Tables["Table 1"];
var table2 = yourDataSet.Tables["Table 2"];
var results = table1.AsEnumerable().Select(t1 => new {
name = t1.Field<string>("Name"),
cost = t1.Field<int>("cost")
})
.Concat(
table2.AsEnumerable().Select(t2 => new {
name = t2.Field<string>("Name"),
cost = t2.Field<int>("cost")
})
)
.GroupBy(m => m.name)
.Select(g => new {
name = g.Key,
cost = g.Sum(x => x.cost)
});
this won't give you a dataTable, but an IEnumerable. To transform an IEnumerable to a dataTable, see for example here
or easier, if table1 and table2 have same rows
var table1 = yourDataSet.Tables["Table 1"];
var table2 = yourDataSet.Tables["Table 2"];
var results = new DataTable();
results.Columns.Add("Name");
results.Columns.Add("cost", typeof(int));
table1.AsEnumerable().Concat(table2.AsEnumerable())
.GroupBy(m => m.Field<string>("Name"))
.Select(g => results.Rows.Add(g.Key, g.Sum(x => x.Field<int>("cost"))));
Related
Below query has 4 columns, out of 4 columns .. i need only 2 columns which are Vegetables, Pricing.. and also .. Pricing has to be order by descending..
How to include order by for the aggregation value in Linq query?
DataTable Dt2 = new DataTable();
Dt2 = dt.AsEnumerable()
.GroupBy(r => r.Field<string>("Vegetables"))
.Select(g =>
{
var row = dt.NewRow();
row["Vegetables"] = g.Key;
row["Pricing"] = g.Average(r => ParseInt32(r.Field<string>("Pricing")));
return row;
}).CopyToDataTable();
Two Linq ways come to mind.
The first is using .OrderBy<T>() followed by .Reverse<T>():
DataTable Dt2 = new DataTable();
Dt2 = dt.AsEnumerable()
.GroupBy(r => r.Field<string>("Vegetables"))
.Select(g =>
{
var row = dt.NewRow();
row["Vegetables"] = g.Key;
row["Pricing"] = g.Average(r => Int32.Parse(r.Field<string>("Pricing")));
return row;
})
.OrderBy(row => row["Pricing"])
.Reverse()
.CopyToDataTable();
The second is just using .OrderByDescending<T>():
DataTable Dt2 = new DataTable();
Dt2 = dt.AsEnumerable()
.GroupBy(r => r.Field<string>("Vegetables"))
.Select(g =>
{
var row = dt.NewRow();
row["Vegetables"] = g.Key;
row["Pricing"] = g.Average(r => Int32.Parse(r.Field<string>("Pricing")));
return row;
})
.OrderByDescending(row => row["Pricing"])
.CopyToDataTable();
If you're looking for a non-Linq solution could also apply a sorted DataView on the DataTable to achieve a similar result.
I want to rearrange query result from db with duplicate data into distinct row (for data display )but having 1 column collect related values in comma separated if more than 1 item found.
For example consider list below (from db query):
ID GROUP DATE
A1212 1 1/1/2019
A1212 2 1/1/2019
A1313 1 3/1/2019
into:
ID GROUP
A1212 1,2
A1313 1
sql string:
select DISTINCT Declaration_Form_Master.*,Declaration_Form_Detail.KPA_Group, Temp_Storage_Reg_V.*,Temp_Storage_Reg_V.ID as TSEID,Users.Company As Uc, 'NULL' as 'CTU_id' from Declaration_Form_Master left outer join Temp_Storage_Reg_V on (Declaration_Form_Master.Master_ID=Temp_Storage_Reg_V.TSEMaster_ID) right join Users on (Declaration_Form_Master.Agent_ID = Users.UserId) right join Declaration_Form_Detail on (Declaration_Form_Master.Master_ID = Declaration_Form_Detail.Master_ID) where Declaration_Form_Master.Confirmation ='1' and Submit_Date >= '2019-01-28' and Submit_Date < '2019-08-30' order by Application_ID DESC
need to join all table because search criteria based on column on multiple table. i cant figure out on sql, but want to rearrange back the result using array or list.
Maybe some algorithm can help.
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
dt.Columns.Add("GROUP", typeof(int));
dt.Columns.Add("DATE", typeof(DateTime));
dt.Rows.Add(new object[] {"A1212", 1, DateTime.Parse("1/1/2019")});
dt.Rows.Add(new object[] {"A1212", 2, DateTime.Parse("1/1/2019")});
dt.Rows.Add(new object[] {"A1213", 1, DateTime.Parse("3/1/2019")});
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(string));
dt2.Columns.Add("GROUP", typeof(string));
var groups = dt.AsEnumerable().GroupBy(x => x.Field<string>("ID")).ToList();
foreach (var group in groups)
{
dt2.Rows.Add(new object[] {
group.Key,
string.Join(",", group.Select(x => x.Field<int>("GROUP").ToString()).Distinct())
});
}
}
}
}
If you want to do this action even in T-SQL you must aggregate the result
By exemple
DECLARE #fakeTable TABLE (ID varchar(50), [GROUP] int)
INSERT INTO #fakeTable
VALUES
('A1212', 1 ),
('A1212', 2 ),
('A1213', 1 )
SELECT
ID,
[GROUP] = stuff((
SELECT ','+convert(varchar(100),[GROUP])
FROM #fakeTable innerTable
WHERE innerTable.ID = orgTable.ID
ORDER BY [GROUP]
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'')
FROM (
SELECT DISTINCT ID FROM #fakeTable
) orgTable
More info about aggregation
DataTable dx = new DataTable();
dx.Columns.Add("Application_ID", typeof(int));
dx.Columns.Add("KPA_Group", typeof(int));
foreach(var z in data) {
dx.Rows.Add(new object[] { z.Application_ID,z.KPA_Group });
}
DataTable dt1 = new DataTable();
dt1.Columns.Add("Application_ID", typeof(string));
dt1.Columns.Add("KPA_Group", typeof(string));
var groups = dx.AsEnumerable().GroupBy(x => x.Field<Int32>("Application_ID")).ToList();
foreach (var group in groups)
{
dt1.Rows.Add(new object[] {
group.Key,
string.Join(",", group.Select(x => x.Field<int>("KPA_Group").ToString()).Distinct())
});
}
foreach (DataRow row in dt1.Rows)
{
#:#row["Application_ID"].ToString() |
#:#row["KPA_Group"] <br />
}
result :
2019080001 | 2,3
2019070002 | 2
2019070001 | 2
2019060001 | 1,2
2019040002 | 2
2019030002 | 2
2019030001 | 2
2019020002 | 2
2019020001 | 2
i dont understand why i can't use CopyToDataTable method. solved this by using foreach.
Hi I have created dynamic table as below and in that I have 2 rows with same id
How should I merge them.
DataTable dt = new DataTable();
dt = (DataTable)Session["AddtoCart"];
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = collection["hdactualquantity"];
dr1["PropertyId"] = collection["hdPropertyId"];
dr1["Quantity"] = collection["Quantity"];
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
My added rows are as
Propertyid, Quantity, ActualQuantity
1 5 10
1 2 10
2 3 20
2 4 20
Th result i needed is as
Propertyid, Quantity, ActualQuantity
1 7 10
2 7 20
Update: i have tried this answer:
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))// issue over this line
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<int>("Title"),
Description = grp.First().Field<int>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Session["AddtoCart"] = SumByIdTable;
but I am getting issue as Specified cast is not valid. on .GroupBy(row => row.Field("PropertyId"))
Update 2: I have tried below code but i am getting issue
DataTable dt = new DataTable();
dt.Columns.Add("PropertyId", typeof(int));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Description", Type.GetType("System.String"));
dt.Columns.Add("Title", Type.GetType("System.String"));
dt.Columns.Add("ActualQuantity", typeof(int));
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = Convert.ToInt32(collection["hdactualquantity"]);
dr1["PropertyId"] = Convert.ToInt32(collection["hdPropertyId"]);
dr1["Quantity"] = Convert.ToInt32(collection["Quantity"]);
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<string>("Title"),
Description = grp.First().Field<string>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Session["AddtoCart"] = SumByIdTable;
but I am getting issue in
SumByIdTable.Rows.Add(x.PropertyId, x.Quantity, x.ActualQuantity,x.Title, x.Description);
Input string was not in a correct format.
Resolved Update 3: I have tried below code and is working
DataTable dt = new DataTable();
dt.Columns.Add("PropertyId", typeof(int));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Description", Type.GetType("System.String"));
dt.Columns.Add("Title", Type.GetType("System.String"));
dt.Columns.Add("ActualQuantity", typeof(int));
DataRow dr1 = dt.NewRow();
foreach (var key in collection.AllKeys)
{
dr1["Description"] = collection["hdDescription"];
dr1["Title"] = collection["hdTitle"];
dr1["ActualQuantity"] = Convert.ToInt32(collection["hdactualquantity"]);
dr1["PropertyId"] = Convert.ToInt32(collection["hdPropertyId"]);
dr1["Quantity"] = Convert.ToInt32(collection["Quantity"]);
TempData["AddedtoCart"] = ConfigurationManager.AppSettings["AddtoCart"].ToString();
}
dt.Rows.Add(dr1);
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("PropertyId"))
.Select(grp => new
{
PropertyId = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity"),
Title = grp.First().Field<string>("Title"),
Description = grp.First().Field<string>("Description")
});
var SumByIdTable = dt.Clone();
foreach (var x in query)
SumByIdTable.Rows.Add(Convert.ToInt32(x.PropertyId), Convert.ToInt32(x.Quantity), x.Description, x.Title, Convert.ToInt32(x.ActualQuantity));
Session["AddtoCart"] = SumByIdTable;
changes was I have to add the value in SumByIdTable as clone set in dt
You can use LINQ (-to-DataTable):
var query = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("Propertyid"))
.Select(grp => new {
Propertyid = grp.Key,
Quantity = grp.Sum(row => row.Field<int>("Quantity")),
ActualQuantity = grp.First().Field<int>("ActualQuantity")
});
var SumByIdTable = dt.Clone();
foreach(var x in query)
SumByIdTable.Rows.Add(x.Propertyid, x.Quantity, x.ActualQuantity);
I try to remove the duplicate rows by select a first row from every group.
For Example
PK Col1 Col2
1 A B
2 A B
3 C C
4 C C
I want a return:
PK Col1 Col2
1 A B
3 C C
I tried following code but it didn't work:
DataTable dt = GetSampleDataTable(); //Get the table above.
dt = dt.Select("SELECT MIN(PK), Col1, Col2 GROUP BY Col1, Col2);
DataTable's Select method only supports simple filtering expressions like {field} = {value}. It does not support complex expressions, let alone SQL/Linq statements.
You can, however, use Linq extension methods to extract a collection of DataRows then create a new DataTable.
dt = dt.AsEnumerable()
.GroupBy(r => new {Col1 = r["Col1"], Col2 = r["Col2"]})
.Select(g => g.OrderBy(r => r["PK"]).First())
.CopyToDataTable();
dt = dt.AsEnumerable().GroupBy(r => r.Field<int>("ID")).Select(g => g.First()).CopyToDataTable();
dt.AsEnumerable()
.GroupBy(r => new { Col1 = r["Col1"], Col2 = r["Col2"] })
.Select(g =>
{
var row = dt.NewRow();
row["PK"] = g.Min(r => r.Field<int>("PK"));
row["Col1"] = g.Key.Col1;
row["Col2"] = g.Key.Col2;
return row;
})
.CopyToDataTable();
This solution sort by Col1 and group by Col2. Then extract value of Col2 and display it in a mbox.
var grouped = from DataRow dr in dt.Rows orderby dr["Col1"] group dr by dr["Col2"];
string x = "";
foreach (var k in grouped) x += (string)(k.ElementAt(0)["Col2"]) + Environment.NewLine;
MessageBox.Show(x);
Based on #Alfred Wallace's solution :
DataTable dt = new DataTable();
dt.Columns.Add("Col1");
dt.Columns.Add("Col2");
dt.Rows.Add("120", "34");
dt.Rows.Add("121", "34");
dt.Rows.Add("122", "34");
dt.Rows.Add("1", "345");
dt.Rows.Add("2", "345");
dt.Rows.Add("3", "345");
var grouped = from DataRow dr in dt.Rows orderby dr["Col1"] group dr by dr["Col2"];
string xxx = "", yyy = "";
foreach (var k_group in grouped)
{
xxx += (string)(k_group.ElementAt(0)["Col1"]) + Environment.NewLine;
foreach (DataRow item_dr in k_group)
{
yyy += (string)(item_dr["Col1"]) + Environment.NewLine;
// or use WhatEverMethod(item_dr);
}
var zzz = k_group.Max(g => g["Col1"]);
var qqq = k_group.Key;
}
I have data being returned in a DataTable that looks like:
Department | EmployeeName
1 | Employee1
1 | Employee1
2 | Employee2
3 | Employee3
3 | Employee3
3 | Employee3
I'm trying to get only distinct rows and put it into a collection, like so:
IEnumerable<Department> departments = dt.AsEnumerable().Select(row =>
new Department
{
DepartmentID = Int32.Parse(row["DepartmentID"].ToString()),
Employee = new Employee { EmployeeName = row["EmployeeName"].ToString() }
}).Distinct();
It should only return 3 rows, but instead it's returning all 6.
What am I doing wrong here?
Not sure but one of the following may work for you ..........
just do this
var distrows= table1.AsEnumerable().Distinct();
will do your task..........than create collection of department form the distrow..
IEnumerable<Department> departments = (from DataRow dRow in distrows
new Department
{
DepartmentID = Int32.Parse(row["DepartmentID"].ToString()),
Employee = new Employee { EmployeeName = row["EmployeeName"].ToString() }
});
OR
var distinctRows = (from DataRow dRow in dTable.Rows
select new {col1=dRow["dataColumn1"],col2=dRow["dataColumn2"]}).Distinct();
IEnumerable<Department> departments = (from DataRow dRow in distrows
new Department
{
DepartmentID = Int32.Parse(distinctRows.col1),
Employee = new Employee { EmployeeName = distinctRows.col2.ToString() }
});
Class/Schema
public class abc
{
public int id;
}
DataTable and Records
DataTable dt = new DataTable();
DataColumn dc = new DataColumn("id", Type.GetType("System.Int32"));
dt.Columns.Add(dc);
DataRow dr = dt.NewRow();
dr["id"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["id"] = 1;
dt.Rows.Add(dr);
Query
var qa = dt.AsEnumerable()
.Select(row => new
{
Id = row.Field<int>("id"),
})
.Distinct();
what i think the problem here is that you are creating different objects with have no implementation for comparing the equality based on some propertiese. so the Distinct() method compares the refference of the objects and hence concludes that all the objects are different because they point to different reffrences.
what you shoud do instead is try parsing the information in an object that implements IEqualityComparer and then use .Select(<IEqualityComparer>).Distinct()