I've a datatable named which contains data with a column of ID, firstname, lastname. Another datatable contains columns of code, userID1, userID2, userID3, work.
Now i want a new datatable which should contain the column of both the datatable with proper data.
New datatable should contain data as: ID, userfullname1, userfullname2, userfullname3, work.
Here we get the value of userfullname1 by firstname, lastname of datatable1 & userID1 of datatable2. Similarly we get the value of userfullname2 by firstname, lastname of datatable1 & userID2 of datatable2 & so on.
The value of ID in Datatable1 is same as userID1, userID2, userID3 in Datatable2.
Finally, i want to obtain a new datatable with code, userfullname1, userfullname2, userfullname3, work. But users IDs are in datatable1. So, i want to bind the names of Datatable1 to the all 3 userids of Datatable2 via their IDs whichare present in both the tables.
Datatable1 :
iD name
1 b
2 d
3 f
4 s
....
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
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
How can i join & get the new datatable ?
It sounds like you have a table with User Ids and you want to join your profile table to get those names. You can do this with sub-queries like:
var myTable = UserIds.Select(u => new
{
User1FullName = u.UserProfiles.FirstOrDefault(p => p.UserId == u.userId1).Select(p => p.FirstName + " " + p.LastName),
User2FullName = u.UserProfiles.FirstOrDefault(p => p.UserId == u.userId2).Select(p => p.FirstName + " " + p.LastName)
// etc...
});
You can do it with joins like:
var myTable = (from u in UserIds
join p1 in UserProfiles on u.UserId1 equals p1.UserId
join p2 in UserProfiles on u.UserId2 equals p2.UserId
// etc...
select new
{
User1FullName = p1.FirstName + " " + p1.LastName,
User2FullName = p2.FirstName + " " + p2.LastName,
// etc...
});
You can use LINQ to achieve what you want:
DataTable tblResult = new DataTable();
tblResult.Columns.Add("ID");
tblResult.Columns.Add("userfullname1");
tblResult.Columns.Add("userfullname2");
tblResult.Columns.Add("userfullname3");
tblResult.Columns.Add("Work");
var query = from r1 in datatable1.AsEnumerable()
from r2 in datatable2.AsEnumerable()
let id = r1.Field<int>("ID")
let userID1 = r2.Field<int>("userID1")
let userID2 = r2.Field<int>("userID2")
let userID3 = r2.Field<int>("userID3")
where id == userID1 && id == userID2 && id == userID3
select new { r1, r2, id, userID1, userID2, userID3 };
foreach (var x in query)
{
DataRow row = tblResult.Rows.Add();
string firstName = x.r1.Field<string>("firstname");
string lastName = x.r1.Field<string>("lastname");
string userfullname1 = string.Format("{0} {1} {2}", firstName, lastName, x.userID1);
string userfullname2 = string.Format("{0} {1} {2}", firstName, lastName, x.userID2);
string userfullname3 = string.Format("{0} {1} {2}", firstName, lastName, x.userID3);
row.SetField("ID", x.id);
row.SetField("userfullname1", userfullname1);
row.SetField("userfullname2", userfullname2);
row.SetField("userfullname3", userfullname3);
row.SetField("Work", x.r2.Field<string>("Work"));
}
If you just want your resulting table to have name and id, you should do it like this:
DataTable dtResult = new DataTable();
dtResult.Columns.Add("ID", typeof(string));
dtResult.Columns.Add("name", typeof(string));
var result = from datatable1 in table1.AsEnumerable()
join datatable2 in table2.AsEnumerable()
on datatable1.Field<string>("ID") equals datatable2.Field<string>("userID")
select dtResult.LoadDataRow(new object[]
{
datatable1.Field<string>("ID"),
string.Format("{0} {1}" ,datatable1.Field<string>("fname") ,datatable1.Field<string>("lname")),
}, false);
result.CopyToDataTable();
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 };
Please i need your help on this module part of my program. i have 2 tables, TableA which has "code,description,value" and TableB which has "code, values" example below :
TableA
code description value
-----------------------------
CD1 BOOKS
CD2 BREADS
CD3 PHONES
CD4 FISH
TableB
code value1 value2 value3 value4
--------------------------------------
cd1 12 21 10 21
cd2 9 10 10 11
cd3 19 11 29 13
cd4 10 12 22 12
the idea is to update TableA with the Values of TableB where TableA.code=TableB.code but if their are values in TableA then Update content of TableA Value field by adding the new values to the old value field where TableB.code = TableA.code. i have written the following code but it's only updating one row, below is my code :
DataTable dt = GetDatafromDatabase(); //===== returns a DataTable
string SQLT = "SELECT * FROM tbl_TempReport";
if (cn.State == ConnectionState.Closed) {cn.Open(); }
SqlCommand cmdT = new SqlCommand(SQLT, cn);
while (rt.Read())
{
// For each row, print the values of each column.
foreach (DataColumn column in dt.Columns)
{
foreach (DataRow row in dt.Rows)
{
colname = column.ColumnName.ToString();
string m_Code = rt["code"].ToString();
if (m_Code == colname) {
if (m_Code == colname && mValue > 0) { mValue += Convert.ToInt32(row[column].ToString()); } else { mValue = Convert.ToInt32(row[column].ToString()); }
//============ insert into tbl_TempReport to match the appropriate column
string SQLP = "UPDATE tbl_TempReport SET VALUEP = #VALUEP WHERE code = #code";
SqlCommand cmdp = new SqlCommand(SQLP, cn);
cmdp.Parameters.AddWithValue("#VALUEP", SqlDbType.Int).Value = mValue;
cmdp.Parameters.AddWithValue("#code", SqlDbType.NVarChar).Value = rt["code"].ToString();
cmdp.ExecuteNonQuery();
}
}
}
}
i need your help to achieve this. Thank you
If I understand the question, this can be done in a single update statement, without any loops:
UPDATE a
SET value = b.value1 + b.value2 + b.value3 + b.value4 + COALESCE(value, 0)
FROM TableA a
INNER JOIN TableB b ON(a.code = b.code)
I have two strongly typed Datatable (dt1):
|FirstName|LastName|Val1|Val2|
|Tony |Stark |34 |35 |
|Steve |Rogers |12 |23 |
|Natasha |Romanoff|2 |100 |
and the second (dt2)
|FirstName|LastName|Val1|Val2|
|Tony |Stark |16 |5 |
|Bruce |Banner |2 |1 |
|Steve |Rogers |54 |40 |
I try to create a new Datatable where I add up the values for the persons. I need a outer join since I need all persons and the value in the second table is halved.
So the result should looks like:
|FirstName|LastName|Val1|Val2|
|Tony |Stark |42 |37.5|
|Steve |Rogers |39 |43 |
|Natasha |Romanoff|2 |100 |
|Bruce |Banner |1 |0.5 |
My approach was with LINQ:
Dim query =
from a in ds1.Table1
Join b in ds2.Table2
On a.FirstName + a.LastName Equals b.FirstName + b.Lastname
Select New With {
.FirstName = a.FirstName,
.LastName = a.LastName,
.Val1 = a.Val1 + b.Val1 *0.5,
.Val2 = a.Val2 + b.Val2 *0.5
}
But I dont get all persons with the approach. I also tried
Dim query =
From a in ds1.Table1
From b in ds2.Table2
Select New With{
Key .KeyName = a.FirstName + a.LastName = b.FirstName + b.FirstName,
.Val1 = a.Val1 + b.Val1 *0.5,
.Val2 = a.Val2 + b.Val2 * 0.5
}
Now I get many entries for each person. Could anyone help me get this done. I dont know if there is maybe another approach without Linq to solve this.
An example using group by. The thing to consider is that before performing the group by and the Sum operation all the values in the second table must be divided by 2. I take care of that before the .Concat
var dt1 = new List<MyClass>();
dt1.Add(new MyClass { FirstName = "Tony", LastName = "Stark", Val1 = 34, Val2 = 35});
dt1.Add(new MyClass { FirstName = "Steve", LastName = "Rogers", Val1 = 12, Val2 = 23});
dt1.Add(new MyClass { FirstName = "Natasha", LastName = "Romanoff", Val1 = 2, Val2 = 100 });
var dt2 = new List<MyClass>();
dt2.Add(new MyClass { FirstName = "Tony", LastName = "Stark", Val1 = 16, Val2 = 5 });
dt2.Add(new MyClass { FirstName = "Bruce", LastName = "Banner", Val1 = 2, Val2 = 1 });
dt2.Add(new MyClass { FirstName = "Steve", LastName = "Rogers", Val1 = 54, Val2 = 40 });
var q = from a in dt1
.Concat(
from b in dt2
select new MyClass
{
FirstName = b.FirstName,
LastName = b.LastName,
Val1 = b.Val1 * 0.5m,
Val2 = b.Val2 * 0.5m
})
group a by new {a.FirstName, a.LastName}
into g
select new
{
g.First().FirstName,
g.First().LastName,
Val1 = g.Sum(x => x.Val1),
Val2 = g.Sum(x => x.Val2),
};
foreach (var s in q)
{
Console.WriteLine("{0} {1} {2} {3}", s.FirstName,s.LastName,s.Val1,s.Val2);
}
Result
Tony Stark 42,0 37,5
Steve Rogers 39,0 43,0
Natasha Romanoff 2 100
Bruce Banner 1,0 0,5
I got it now. My Solution is:
Dim qLeft = From a in dt1.Getdt1Info
Group Join b in dt2.Getdt2Info
On a.FirstName + a.LastName Equals b.FirstName + b.LastName
Into NewGroup = Group
From c in NewGroup.DefaultIfEmpty
Select New With{
.Name = a.FirstName + ", " + a.LastName,
.Value1 = a.Val1 + If (c is nothing, 0D, c.Val1) * 0.5,
.Value2 = a.Val2 + If (c is nothing, 0D, c.Val2) * 0.5
}
Dim qRight =From a in dt2.Getdt2Info
Group Join b in dt1.Getdt1Info
On a.FirstName + a.LastName Equals b.FirstName + b.LastName
Into NewGroup = Group
From c in NewGroup.DefaultIfEmpty
Select New With{
.Name = a.FirstName + ", " + a.LastName,
.Value1 = a.val1 * 0.5 + If (c Is Nothing, 0D, c.Val1),
.Value2 = a.val2 * 0.5 + If (c Is Nothing, 0d, c.Val2)}
Dim qFull = qleft.Concat(qRight).GroupBy(function(x) x.Name).Select(function(x) x.First)
I still dont know why qleft.Union(qRight) doesnt eliminate the duplicates. I solved that with the functions (s. Code).
I have a trouble with Linq Join. I want to join 2 tables, which they have same structure with n-columns. My problem is i don't know the names of those columns, so how can i rewrite those in select new?
Table 1: Here I have some parameters in ID, Name and LastName. Comment, Attribute and the rest are null
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
3 lola
1 de
4 miki
... ... ... ...
Table 2: Here is the same like Table 1 but it has some parameters in Comment, Attribute and the Rest.
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
1 de "hi"
4 miki "OKK"
3 lola "yo" "LL"
Result: I would like to have joined Table like this
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
3 lola "yo" "LL"
1 de "hi"
4 miki "OKK"
... ... ... ... ... ...
My Code would be:
var Result= from tb1 in table1.AsEnumerable()
join tb2 in tabl2.AsEnumerable()
on new
{
Name = tb1.Field<String>("Name"),
LastName = tb1.Field<String>("LastName"),
} equals new
{
Name=tb2.Field<String>("Name"),
LastName=tb2.Field<String>("LastName"),
}
into grp1
from tb3 in grp1.DefaultIfEmpty()
select new
{
ID = tb1.Field<String>("ID"),
Name = tb1.Field<String>("Name") ,
LastName = tb1.Field<String>("LastName"),
Comment = tb3!= null ? tb3.Field<String>("Comment") : null,
Attribute= tb3!= null ? tb3.Field<String>("Attribute") : null,
...
// Here should be next Columns Name but don't know how to put there
};
I tried with this code but my compiler just hanged out, dont know why
for (int i = 2; i < table1.Rows.Count; i++)
{
foreach (DataRow dr in table2.Rows)
{
if ((table1.Rows[i]["Name"].ToString() == dr["Name"].ToString())&&table1.Rows[i]["LastName"].ToString() == dr["LastName"].ToString())
{
table1.Rows.RemoveAt(i);
table1.ImportRow(dr);
}
}
}
dataGridView1.DataSource = table1;
For each row1 in table1, if there is a matching row2 in table2, use row2. Otherwise, use row1.
var newTable = table1.Clone();
foreach (DataRow row1 in table1.Rows) // To skip the first 2, use table1.Rows.Cast<DataRow>().Skip(2)
{
var row = table2.Rows.Cast<DataRow>().FirstOrDefault(row2 =>
row1["Name"].ToString() == row2["Name"].ToString() &&
row1["LastName"].ToString() == row2["LastName"].ToString()) ?? row1;
newTable.ImportRow(row);
}
dataGridView1.DataSource = newTable;
How about joining as you did and then copying the three known fields from table1's rows to table2's rows?
var copiedTable2 = table2.Copy(); // Copy table2 if you don't want it to be modified
var items = from tb1 in table1.AsEnumerable()
join tb2 in copiedTable2.AsEnumerable()
on new
{
Name = tb1.Field<String>("Name"),
LastName = tb1.Field<String>("LastName"),
} equals new
{
Name=tb2.Field<String>("Name"),
LastName=tb2.Field<String>("LastName"),
}
into grp1
from tb3 in grp1.DefaultIfEmpty()
select new
{
ID = tb1.Field<String>("ID"),
Name = tb1.Field<String>("Name") ,
LastName = tb1.Field<String>("LastName"),
Row = tb3 ?? table2.NewRow();
};
foreach(var item in items)
{
item.Row.SetField<String>("ID", item.ID);
item.Row.SetField<String>("Name", item.Name);
item.Row.SetField<String>("LastName", item.LastName);
}
var rows = items.Select(x => x.Row);
// How to set the rows as a DataGridView's DataSource
var result = table2.Clone();
foreach(var row in rows)
{
result.Rows.Add(row.ItemArray);
}
dataGridView.DataSource = result;
Try this, no need of using loops
var resultTable = from tb1 in table1.AsEnumerable()
join tb2 in tabl2.AsEnumerable()
on tb1["Name"].ToString() equals tb2["Name"].ToString()
where tb1["LastName"].ToString() == tb2["LastName"].ToString()
select r;
DataTable resultTable =result.CopyToDataTable();
I want to group in Datatable by Name, LastName and the rest should be in same row. Can someone help me with it?
My DataTable:
Name LastName 1 3 2
kiki ha FF
lola mi AA
ka xe UU
kiki ha SS
I want to have DataTable group by Name:
Name LastName 1 3 2
kiki ha FF SS
lola mi AA
ka xe UU
My new code:
var result11 = from t1 in newtable.AsEnumerable()
group t1 by new { Name = t1.Field<String>("Name"), LastName = t1.Field<String>("LastName") } into grp
select new
{
Name = grp.Key.Name,
LastName = grp.Key.LastName,
//Something must be there
};
Add these lines instead of the comment (//something must be there):
C1 = String.Join(",", grp.Select(r=>r.Field<String>("1"))),
C2 = String.Join(",", grp.Select(r=>r.Field<String>("2"))),
C3 = String.Join(",", grp.Select(r=>r.Field<String>("3")))
to get three new columns on the output that aggregate values from the columns 1, 3 and 2.
If you have multiple values in one of the columns for a group, all the values will be shown and separated by comma (,).
If you are sure that there's at most one value per column per group, then you can simply do:
C1 = grp.Max(r => r.Field<String>("1")),
C3 = grp.Max(r => r.Field<String>("3")),
C2 = grp.Max(r => r.Field<String>("2"))
If you want a DataTable as result, this gives your desired result:
var lastNameGroups = from row in table1.AsEnumerable()
group row by new {
Name= row.Field<String>("Name"),
LastName = row.Field<String>("LastName")
} into LastNameGroups
select LastNameGroups;
var table2 = table1.Clone();
foreach (var lng in lastNameGroups)
{
var row = table2.Rows.Add();
row.SetField("Name", lng.Key.Name);
row.SetField("LastName", lng.Key.LastName);
var ones = lng.Where(r => !string.IsNullOrEmpty(r.Field<String>("1")));
if(ones.Any())
row.SetField("1", ones.First().Field<String>("1"));
var twos = lng.Where(r => !string.IsNullOrEmpty(r.Field<String>("2")));
if (twos.Any())
row.SetField("2", twos.First().Field<String>("2"));
var threes = lng.Where(r => !string.IsNullOrEmpty(r.Field<String>("3")));
if (threes.Any())
row.SetField("3", threes.First().Field<String>("3"));
}