I have an issue with joining two datatables for example:
table1 table2
ID, name ID, stock
1, item1 1, blabla
1, item2 3, bla2
3, item3
After left join it should looking like this:
table3
ID, name, stock
1, item1, blabla
1, item2, blabla
3, item3, bla2
but it looks like this:
table3
ID, name, stock
1, item1,
1, item2,
3, item3,
This is mine code:
var rowDataLeftOuter = from rowLeft in dtblLeft.AsEnumerable()
join rowRight in dtblRight.AsEnumerable() on rowLeft[colToJoinOn] equals rowRight[strTempColName] into gj
from subRight in gj.DefaultIfEmpty()
select rowLeft.ItemArray.Concat((subRight == null) ? (dtblRight.NewRow().ItemArray) : subRight.ItemArray).ToArray();
foreach (object[] values in rowDataLeftOuter)
dtblResult.Rows.Add(values);
Orginal code
Not sure what the value of the columns are in the join - colToJoinOn, strTempColName However the following gives the result you're looking for:
const string columnNameId = "Id";
var dtblLeft = new DataTable();
dtblLeft.Columns.Add(new DataColumn(columnNameId, typeof(int)));
dtblLeft.Columns.Add(new DataColumn("Name", typeof(string)));
var dr1 = dtblLeft.NewRow();
dr1[columnNameId] = 1;
dr1["Name"] = "item1";
dtblLeft.Rows.Add(dr1);
var dr2 = dtblLeft.NewRow();
dr2[columnNameId] = 1;
dr2["Name"] = "item2";
dtblLeft.Rows.Add(dr2);
var dr3 = dtblLeft.NewRow();
dr3[columnNameId] = 3;
dr3["Name"] = "item3";
dtblLeft.Rows.Add(dr3);
var dtblRight = new DataTable();
dtblRight.Columns.Add(new DataColumn(columnNameId, typeof(int)));
dtblRight.Columns.Add(new DataColumn("Stock", typeof(string)));
var dr4 = dtblRight.NewRow();
dr4[columnNameId] = 1;
dr4["Stock"] = "blabla";
dtblRight.Rows.Add(dr4);
var dr5 = dtblRight.NewRow();
dr5[columnNameId] = 3;
dr5["Stock"] = "bla2";
dtblRight.Rows.Add(dr5);
var dtblResult = new DataTable();
dtblResult.Columns.Add(new DataColumn(columnNameId, typeof(int)));
dtblResult.Columns.Add(new DataColumn("Name", typeof(string)));
dtblResult.Columns.Add(new DataColumn("Stock", typeof(string)));
var result = from rowLeft in dtblLeft.AsEnumerable()
join rowRight in dtblRight.AsEnumerable() on rowLeft[columnNameId] equals rowRight[columnNameId] into gj
from subRight in gj.DefaultIfEmpty()
select dtblResult.NewRow().ItemArray = new[]
{
rowLeft[columnNameId],
rowLeft["Name"],
subRight?["Stock"] ?? ""
};
foreach (var dataRow in result)
{
dtblResult.Rows.Add(dataRow);
}
Related
I joined a 2 data tables based on the EMP column and used copytodatatable, however when i load the new datatable into datagridview it only shows the joined columns(salarydt) from the query, why is this??
var collection = from p in dt.AsEnumerable()
join q in salaryDT.AsEnumerable() on p.Field<int>("Emp") equals q.Field<int>("Emp1") into UP
from t in UP
select t;
DataTable resultdt = new DataTable();
dt = collection.CopyToDataTable();
DataTable itself is perfectly geared to merging itself with another data table, using its, well, Merge method. Here's a litte example:
var dt1 = new DataTable("a");
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("Item1", typeof(int));
dt1.PrimaryKey = new[] { dt1.Columns[0] };
var dt2 = new DataTable("a");
dt2.Columns.Add("ID", typeof(int));
dt2.Columns.Add("Item2", typeof(int));
dt2.PrimaryKey = new[] { dt2.Columns[0] };
for (int i = 0; i < 10; i++)
{
dt1.Rows.Add(new object[] { i, i });
dt2.Rows.Add(new object[] { i, i + 10 });
}
dt1.Merge(dt2);
Now dt1 has three columns, ID, Item1, and Item2.
ID Item1 Item2
0 0 10
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
6 6 16
7 7 17
8 8 18
9 9 19
Maybe what you should to do is just return a custom list of items:
Option 1
var data = new Employee[] { new Employee { Id = 1, Name = "John Doe" } };
var data2 = new Salary[] { new Salary { Id = 1, Wage = "$ 50,000.00" } };
var collection = from p in data
join q in data2 on p.Id equals q.Id
select new { Id = p.Id, Name = p.Name, Wage = q.Wage };
Please check the example: link
Option 2
var data = new Employee[] { new Employee { Id = 1, Name = "John Doe" } };
var data2 = new Salary[] { new Salary { Id = 1, Wage = "$ 50,000.00" } };
var collection = from p in data
join q in data2 on p.Id equals q.Id
select new { p, q };
I have 2 datatables.
DataTable wdt = new DataTable();
wdt.Columns.Add("wName", typeof(string));
wdt.Columns.Add("userID1", typeof(string));
wdt.Columns.Add("userID2", typeof(string));
wdt.Columns.Add("userID3", typeof(string));
wdt.Columns.Add("dttime", typeof(DateTime));
DataTable mdt = new DataTable();
mdt.Columns.Add("iD", typeof(string));
mdt.Columns.Add("firstname", typeof(string));
mdt.Columns.Add("lastname", typeof(string));
DataTable dt = new DataTable();
dt.Columns.Add("wName", typeof(string));
dt.Columns.Add("user1", typeof(string));
dt.Columns.Add("user2", typeof(string));
dt.Columns.Add("user3", typeof(string));
dt.Columns.Add("dttime", typeof(DateTime));
for (int i = 0; i < wdt.Rows.Count; i++)
{
DataRow ndr = dt.NewRow();
ndr[0] = wdt.Select()[i][0].ToString();
ndr[1] = (from r in mdt.AsEnumerable()
where r.Field<int>("iD") == Convert.ToInt32(wdt.Rows[i][1])
select r.Field<string>("firstName") + " " + r.Field<string>("lastName")).First<string>();
ndr[2] = (from r in mdt.AsEnumerable()
where r.Field<int>("iD") == Convert.ToInt32(wdt.Rows[i][2])
select r.Field<string>("firstName") + " " + r.Field<string>("lastName")).First<string>();
ndr[3] = (from r in mdt.AsEnumerable()
where r.Field<int>("iD") == Convert.ToInt32(wdt.Rows[i][3])
select r.Field<string>("firstName") + " " + r.Field<string>("lastName")).First<string>();
ndr[4] = wdt.Select()[i][4].ToString();
dt.Rows.Add(ndr);
}
In the above code, i get a new datatable dt from calculating the data from wdt & mdt. But here, i have to run the LINQ syntaxes in a loop. Is it possible to avoid loop & the same work to be done in a single LINQ loop?
Datatable1 :
iD firstname lastname
1 b v
2 d c
3 f g
4 s o
....
Datatable2 :
Code userid1 userid2 userid3 work
1f 1 3 6 gg
2g 1 4 7 gg
3b 3 4 7 gg
4v 4 3 8 gg
Expected New Datatable :
Code username1 username2 username3 work
1f a b c gg
2g d f r gg
3b c h g gg
4v d s h gg
Here, iD from datatable1 & userID1, userID2, userID3 are same.
username1 you can Make a query using left join and return new on the fly object witch have all property you need as below
var newData = (from a in wdt.AsEnumerable()
join user1Info in mdt.AsEnumerable() on a["userID1"] equals user1Info["iD"] into lUser1Info
join user2Info in mdt.AsEnumerable() on a["userID2"] equals user2Info["iD"] into lUser2Info
join user3Info in mdt.AsEnumerable() on a["userID3"] equals user3Info["iD"] into lUser3Info
from user1Info in lUser1Info.DefaultIfEmpty()
from user2Info in lUser2Info.DefaultIfEmpty()
from user3Info in lUser3Info.DefaultIfEmpty()
select new
{
wName = a["wName"].ToString(),
username1 = user1Info == null ? string.Empty : user1Info["firstname"].ToString() + user1Info["lastname"],
username2 = user2Info == null ? string.Empty : user2Info["firstname"].ToString() + user2Info["lastname"],
username3 = user3Info == null ? string.Empty : user3Info["firstname"].ToString() + user3Info["lastname"],
dttime = a["dttime"]
}).ToList();
I have two DataTables and I want to display the rows. if both the datatables having the same value, Then mark X in all columns or else select the column with highest value(Eg:DT1: 10,DT2 :5)
Datatable1
id Name Weight
1 Ship 500
2 Train 600
3 Plane 700
4 Car 800
Datatable2
id Name Weight
1 Ship 500
3 Plane 600
4 Car 200
I want the result to be:
Datatable3
id Name Weight Datatable1 Datatable2
1 Ship 500 X X
2 Train 600 X
3 Plane 700 X X
4 Car 800 X
I have tried the below:-
DataTable Datatable3 = (from a in Datatable1.AsEnumerable()
join b in Datatable2.AsEnumerable()
on a["Name"].ToString() equals b["Name"].ToString()
a["Weight"].ToString() equals b["Weight"].ToString() into g
where g.Count() != 1 select a).CopyToDataTable();
dataGrid1.ItemsSource = Datatable3.DefaultView;
Please help me on this. Thanks in advance
This is what I have:-
DataTable Datatable3 = dt1.AsEnumerable().Union(dt2.AsEnumerable())
.GroupBy(x => x.Field<int>("Id"))
.Select(x =>
{
var topWeightItem = x.OrderByDescending(z => z.Field<int> ("Weight")).First();
return new Items
{
Id = x.Key,
Name = topWeightItem.Field<string>("Name"),
Weight = topWeightItem.Field<int>("Weight"),
DataTable1 = dt1.AsEnumerable().Any(z => z.Field<int>("Id") == x.Key
&& z.Field<int>("Weight") == topWeightItem.Field<int>("Weight")
&& z.Field<string>("Name") == topWeightItem.Field<string>("Name"))
? "X" : String.Empty,
DataTable2 = dt2.AsEnumerable().Any(z => z.Field<int>("Id") == x.Key
&& z.Field<int>("Weight") == topWeightItem.Field<int>("Weight")
&& z.Field<string>("Name") == topWeightItem.Field<string>("Name"))
? "X" : String.Empty
};
}
).PropertiesToDataTable<Items>();
Since It is returning an anonymous type, you can't use CopyToDataTable method, so please check this to understand how I converted it into a datatable.
I am getting this output:-
I have used following type for conversion purpose:-
public class Items
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Weight { get; set; }
public string DataTable1 { get; set; }
public string DataTable2 { get; set; }
}
I have written in two query to achieve what you said..Perhaps you can optimize it further.
//datatable1
DataTable dt1 = new DataTable();
dt1.Columns.Add("Id");
dt1.Columns.Add("Name");
dt1.Columns.Add("Weight");
DataRow dr ;
dr = dt1.NewRow();
dr["Id"] = 1;
dr["Name"] = "Ship";
dr["Weight"] = 500;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 2;
dr["Name"] = "Train";
dr["Weight"] = 600;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 3;
dr["Name"] = "Plane";
dr["Weight"] = 700;
dt1.Rows.Add(dr);
dr = dt1.NewRow();
dr["Id"] = 4;
dr["Name"] = "Car";
dr["Weight"] = 400;
dt1.Rows.Add(dr);
//datatable2
DataTable dt2 = new DataTable();
dt2.Columns.Add("Id");
dt2.Columns.Add("Name");
dt2.Columns.Add("Weight");
DataRow dr2;
dr2 = dt2.NewRow();
dr2["Id"] = 1;
dr2["Name"] = "Ship";
dr2["Weight"] = 500;
dt2.Rows.Add(dr2);
dr2 = dt2.NewRow();
dr2["Id"] = 3;
dr2["Name"] = "Plane";
dr2["Weight"] = 700;
dt2.Rows.Add(dr2);
dr2 = dt2.NewRow();
dr2["Id"] = 4;
dr2["Name"] = "Car";
dr2["Weight"] = 400;
dt2.Rows.Add(dr2);
//iterate through table1
IEnumerable<DataRow> table1 = from r in dt1.AsEnumerable()
select r;
//iterate through table2
IEnumerable<DataRow> table2 = from r in dt2.AsEnumerable()
select r;
Console.WriteLine("Id\tName\tWeight\tDatatable1\tDatatable2");
Console.WriteLine("----------------------------------------------------");
//prints the common records
foreach (DataRow td1 in table1.Distinct())//Matches wholes of the Element Sequence inside IEnumerable
{
table2.Distinct().ToList().ForEach(td2 =>
{
if (td1.Field<string>("Id") == td2.Field<string>("Id"))
{
Console.WriteLine(td1.Field<string>("Id") + "\t" + td1.Field<string>("Name") + "\t" + td1.Field<string>("Weight") + "\t" + "x" + "\t\t" + "x");
}
});
}
//prints the missing records
var query = (from tb1 in dt1.AsEnumerable()
join tb2 in dt2.AsEnumerable()
on tb1.Field<string>("Id") equals tb2.Field<string>("Id") into subset
from sc in subset.DefaultIfEmpty()
where sc == null
select new
{
id = tb1.Field<string>("Id"),
name = tb1.Field<string>("Name"),
wt = tb1.Field<string>("Weight")
}).Distinct();
foreach (var td1 in query)
{
Console.WriteLine(td1.id + "\t" + td1.name + "\t" + td1.wt + "\t" + "x" + "\t\t" + "-");
}
I have a datatable that looks like below
My result Should be A=40% , B=60% .. ie 2/5 and 3/5
Group name can be A, B, C, etc...
How can i calculate the figures based on that datatable values??
You could use LINQ and cast it to a dictionary:
DataTable dt = new DataTable("test1");
dt.Columns.AddRange(new DataColumn[] { new DataColumn("TASKID"), new DataColumn("GROUPID"), new DataColumn("GROUPNAME") });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 13, 3, "B" });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 14, 3, null });
dt.Rows.Add(new object[] { 15, 3, "B" });
var query = (from DataRow row in dt.Rows
group row by row["GROUPNAME"] into g
select g).ToDictionary(x => (x.Key.ToString() == "" ? "*" : x.Key.ToString()), x => (int)((x.Count() * 100) / dt.Rows.Count));
Iterate through the dictionary to display the values:
foreach(KeyValuePair<string,int> kvp in query)
Console.WriteLine(kvp.Key + " - " + kvp.Value.ToString());
The output:
A - 40
B - 40
* - 20
The percentage is cast as an int. simply change (int)((x.Count() * 100) / dt.Rows.Count) if you need more accurate values.
A simple way, through loop. The following should be similar to the one you require.
//Simulated datatable
DataTable table1 = new DataTable();
table1.Columns.Add(new DataColumn("TaskID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupName", typeof(String)));
//Entered test values
DataRow dr1 = null;
dr1 = table1.NewRow();
dr1["TaskID"] = 12;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 13;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 14;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 15;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 16;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
//solution starts from here
Dictionary<string, int> totalCount = new Dictionary<string, int>();
for (int i = 0; i < table1.Rows.Count; i++)
{
if (totalCount.Keys.Contains(table1.Rows[i]["GroupName"].ToString()))
{
int currVal = totalCount[table1.Rows[i]["GroupName"].ToString()];
totalCount[table1.Rows[i]["GroupName"].ToString()] = currVal + 1;
}
else
{
totalCount[table1.Rows[i]["GroupName"].ToString()] = 1;
}
}
foreach (var item in totalCount)
{
MessageBox.Show(item.Value.ToString());
}
OR
//solution starts from here
var data = table1.AsEnumerable().GroupBy(m => m.Field<string>("GroupName")).Select(grp => new
{
GroupName = grp.Key,
Count = (int)grp.Count()
}).ToList();
Hope this helps
Use Linq
var data=datatable.AsEnumerable().GroupBy(m => m.Field<string>("GROUPNAME")).Select(grp => new
{
GROUPNAME= grp.Key,
Count = (int)grp.Count()
});
My Table1 has some Header and Values:
KundeID KundeName Produkt Comment
1 Michael Jogurt "nichts"
2 Raj "Ich bin cool"
3 Gary Fanta "yahoo"
4 Miky Sprite
I want to change to Table2, make Values from Produkt as Header Columns:
KundeID KundeName Comment Jogurt Fanta Sprite
1 Michael "nichts" x
2 Raj "Ich bin cool"
3 Gary "yahoo" x
4 Miky x
My code for Table1:
DataTable table = new DataTable("Kunde");
table.Columns.Add("KundeID", typeof(Int32));
table.Columns.Add("KundeName", typeof(String));
table.Columns.Add("Produkt", typeof(String));
DataTable comment = new DataTable("Comment");
comment.Columns.Add("KundeName", typeof(String));
comment.Columns.Add("Comment", typeof(String));
DataSet ds = new DataSet("DataSet");
ds.Tables.Add(table);
ds.Tables.Add(comment);
object[] o1 = { 1, "Michael", "Jogurt" };
object[] o2 = { 2, "Raj" };
object[] o3 = { 3, "Gary", "Fanta" };
object[] o4 = { 4, "Miky", "Sprite" };
object[] c1 = { "Raj", "Ich bin cool" };
object[] c2 = { "Gary", "yahoo" };
object[] c3 = { "Michael", "nichts" };
table.Rows.Add(o1);
table.Rows.Add(o2);
table.Rows.Add(o3);
table.Rows.Add(o4);
comment.Rows.Add(c1);
comment.Rows.Add(c2);
comment.Rows.Add(c3);
var results = from table1 in table.AsEnumerable()
join table2 in comment.AsEnumerable()
on table1.Field<string>("KundeName") equals table2.Field<string>("KundeName") into prodGroup
from table4 in prodGroup.DefaultIfEmpty()
select new
{
KundeID = table1.Field<Int32?>("KundeID"),
KundeName = table1.Field<String>("KundeName"),
Produkt = table1.Field<String>("Produkt"),
Comment = table4 != null ? table4.Field<String>("Comment") : null,
};
dataGridView1.DataSource = results.ToList();
How can I take Value from "Produkt" and make it Header? thank you guys for helping
This should do the trick regardless of how many different products come up. It's pretty short and concise.
// build the new data table
var result = new DataTable();
result.Columns.Add("KundeID", typeof(Int32));
result.Columns.Add("KundeName", typeof(String));
result.Columns.Add("Comment", typeof(String));
result.Columns.AddRange(
(from c in
(from r in table.AsEnumerable()
where !r.IsNull("Produkt") && !string.IsNullOrEmpty(r.Field<string>("Produkt"))
select r.Field<string>("Produkt")).Distinct() // added DISTINCT
select new DataColumn(c, typeof(bool))).ToArray()
);
foreach (var r in results)
{
var productIndex = result.Columns.IndexOf(r.Produkt);
var vals = new List<object>() { r.KundeID, r.KundeName, r.Comment };
for (int i = 3; i < result.Columns.Count; i++)
{
if (i == productIndex)
{
vals.Add(true);
}
else
{
vals.Add(false);
}
}
result.LoadDataRow(vals.ToArray(), true);
}
var products = table.AsEnumerable()
.GroupBy(c => c["Produkt"])
.Where(g => !(g.Key is DBNull))
.Select(g => (string)g.Key)
.ToList();
var newtable = table.Copy();
products.ForEach(p=>newtable.Columns.Add(p,typeof(bool)));
foreach (var row in newtable.AsEnumerable())
{
if (!(row["Produkt"] is DBNull)) row[(string)row["Produkt"]] = true;
}
newtable.Columns.Remove("Produkt");
Try following...this may help you....
DataTable table = new DataTable("Kunde");
table.Columns.Add("KundeID", typeof(Int32));
table.Columns.Add("KundeName", typeof(String));
table.Columns.Add("Produkt", typeof(String));
table.Columns.Add("Comment", typeof(String));
object[] o1 = { 1, "Michael", "Jogurt", "nichts" };
object[] o2 = { 2, "Raj","","Ich bin cool" };
object[] o3 = { 3, "Gary", "Fanta","yahoo" };
object[] o4 = { 4, "Miky", "Sprite","" };
table.Rows.Add(o1);
table.Rows.Add(o2);
table.Rows.Add(o3);
table.Rows.Add(o4);
Dictionary<int,string> dictObj=new Dictionary<int, string>();
for (int i = 0; i < table.Rows.Count; i++)
{
dictObj.Add(Convert.ToInt32(table.Rows[i][0].ToString()), table.Rows[i][2].ToString());
}
foreach (var obj in dictObj)
{
if (string.IsNullOrEmpty(obj.Value))
{
table.Columns.Add(obj.Value, typeof(String));
DataRow row = table.Rows[obj.Key];
row[obj.Value] = "X";
}
}