Select all combinations of the rows from 2 tables - c#

I have two datatables like this:
dt1:
ID1
----------
1
2
3
4
5
6
7
8
9
10
dt2:
ID2
----------
1
2
3
4
5
Now, I want to retrieve all combinations of the items from these two datatables such that the result will contain 50 (10 x 5) rows - something like this:
dtResult:
ID1 ID2
------------
1 1
1 2
1 3
1 4
1 5
2 1
2 2
2 3
2 4
2 5
3 1
. .
. .
. .
is there any simple way instead of using a loop?

You are finding for cartesian product. Use CROSS JOIN
Select a.ID1, b.ID2
FROM dt1 A CROSS JOIN dt2 B

Do a full join:
Select a.ID1, b.ID2 FROM dt1 A,dt2 B

LINQ:
var combinedRows = from a in dt1.AsEnumerable()
from b in dt2.AsEnumerable()
select new { ColumnID1 = a["ID1"], ColumnID2 = b["ID2"] };
foreach (var item in combinedRows)
{
row = dt3.NewRow();
row["ID1"] = item.ColumnID1;
row["ID2"] = item.ColumnID2;
dt3.Rows.Add(row);
}

Use
DataTable dt1 = new DataTable();
dt1.Columns.AddRange(new DataColumn[] {
new DataColumn("ID1") });
for (int i = 0; i < 10; i++)
dt1.Rows.Add(i + 1);
DataTable dt2 = new DataTable();
dt2.Columns.AddRange(new DataColumn[] {
new DataColumn("ID2") });
for (int i = 0; i < 5; i++)
dt2.Rows.Add(i + 1);
var queryOne = from row in dt1.AsEnumerable()
from row1 in dt2.AsEnumerable()
select new
{
id1 = row.Field<string>("ID1"),
id2 = row1.Field<string>("ID2")
};
var result = queryOne.ToList();

Thanks all but i have solved it by Foreach method in LINQ.

Related

Linq into clause returning only columns from joined table

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 };

Merge two datatables in C#?

I have two datatables ..
DataTable dtTemp= new DataTable();
dtTemp.Columns.AddRange(new[]
{
new DataColumn("segment_id", typeof(int)),
new DataColumn("seg_description")
});
DataTable dtTemp2 = new DataTable();
dtTemp2.Columns.Add("set_id",typeof(int));
Now lets have some rows into first table..
segment_id|seg_description
------ |---------------
1 | desc..
2 | desc2..
3 | desc3..
Now lets have some data into second table..
set_id
--------
1
--------
2
Now, I want marge this two tables to get below output
set_id | segment_id |seg_description
--------| ---------- | --------------
1 | 1 | desc..
1 | 2 | desc2..
1 | 3 | desc3..
2 | 1 | desc..
2 | 2 | desc2..
2 | 3 | desc3..
How can I do this?using Merge() can I achieve this?
So you want to "cross-join" the tables by building a cartesian product of all rows? Of course there is no builtin way, you can use this method:
public static DataTable CrossJoinTables(DataTable t1, DataTable t2)
{
if (t1 == null || t2 == null)
throw new ArgumentNullException("t1 or t2", "Both tables must not be null");
DataTable t3 = t1.Clone(); // first add columns from table1
foreach (DataColumn col in t2.Columns)
{
string newColumnName = col.ColumnName;
int colNum = 1;
while (t3.Columns.Contains(newColumnName))
{
newColumnName = string.Format("{0}_{1}", col.ColumnName, ++colNum);
}
t3.Columns.Add(newColumnName, col.DataType);
}
IEnumerable<object[]> crossJoin =
from r1 in t1.AsEnumerable()
from r2 in t2.AsEnumerable()
select r1.ItemArray.Concat(r2.ItemArray).ToArray();
foreach(object[] allFields in crossJoin)
{
t3.Rows.Add(allFields);
}
return t3;
}
Usage:
DataTable tblresult = CrossJoinTables(dtTemp2, dtTemp); // swapped order because you want columns from dtTemp2 first
To do this you need to use the CROSS JOIN operation.
Select * Table1 CROSS JOIN Table2
It literally gives you the product of the two tables : Every row in A joined to every row in B. if A has 100 rows and B has 100 rows, the Cross Join has 10,000 rows.
How about this:
var dt1 = dtTemp1.AsEnumerable();
var dt2 = dtTemp2.AsEnumerable();
var q = from x in dt1
from y in dt2
select new { set_id = (int)y["set_id"], segment_id = (int)x["segment_id"], seg_description = (string)x["seg_description"] };

LINQ query for grouping a table based on the values from another table

I am trying write C# LINQ to join a table based on the values from a different table
For example, I have two tables Table1 and Table2 as below
Table1
Id Name Address StatusId SubStatusId Dubs
1 ABC XYZ 1 39 10
2 PQR XYZ 1 39 0
3 ME WWW 2 39 5
4 YOU XYZ 1 22 0
5 HE XYZ 2 22 5
6 SHE WWW 2 41 0
7 XAZ XYZ 1 39 10
Table2
Id StatusId SubStatusId Status SubStatus Type
1 1 39 Dispense Ready 1
2 1 39 Fill Ready 2
3 2 22 Ship Active 0
4 2 41 Del Pending 0
5 1 22 Verify Pending 0
6 2 39 Benefit None 0
Now, I am trying to join both tables with StatusId and SubstatusId Columns as follows
from p in context.Table1
join label in context.Table2 on new
{
p.StatusId,
p.SubStatusId,
I = p.Dubs== 0,
J = p.Dubs> 0
} equals
new
{
label.StatusId,
label.SubStatusId,
I = label.type== 1
J = label.type== 2
} into gj
from label in gj.DefaultIfEmpty()
The above code join two tables by four values properties but I would like to exclude I and J when type of the row in Table2 is zero no matters what value is in Dubs
Result looks like below
Status SubStatus
Fill Ready (1,39 Since Dubs>0 for which means should return row with type 2)
Dispense Ready (1,39 Since Dubs=0 for which means should return row with type 1)
Benefit None (2, 39 Since type=0, this should ignore Dubs)
Verify Pending (same as above)
Ship Active
Del Pending
Fill Ready (1,39 Since Dubs>0 for which means should return row with type 2)
I would keep the more complex predicates out of the join:
from p in context.Table1
join label in context.Table2 on new
{
p.StatusId,
p.SubStatusId,
} equals new
{
label.StatusId,
label.SubStatusId,
} into gj
from label in gj.DefaultIfEmpty()
where label.Type == 0
|| label.Type == (p.Dubs == 0 ? 1 : 2)
select ...
The join syntax seems easier to control inside of a Where.
The where doesn't match yours, but you should be able to build the complex clause based upon this more easily.
var aresult = from a in ta.AsEnumerable()
from b in tb.AsEnumerable()
.Where(b => a.Field<string>("StatusId") == b.Field<string>("StatusId")
&& a.Field<string>("SubStatusId") == b.Field<string>("SubStatusId"))
select new object[] { a.Field<string>("Name")
,b.Field<string>("Status")
,b.Field<string>("SubStatus")
};
Code to generate tables given ...
DataTable ta = new DataTable();
ta.Columns.Add("Id");
ta.Columns.Add("Name");
ta.Columns.Add("Address");
ta.Columns.Add("StatusId");
ta.Columns.Add("SubStatusId");
ta.Columns.Add("Dubs");
DataTable tb = new DataTable();
tb.Columns.Add("Id");
tb.Columns.Add("StatusId");
tb.Columns.Add("SubStatusId");
tb.Columns.Add("Status");
tb.Columns.Add("SubStatus");
tb.Columns.Add("Type");
string[] tas =
{
"1,ABC,XYZ,1,39,10"
,"2,PQR,XYZ,1,39,20"
,"3,ME,WWW,2,39,0"
,"4,YOU,XYZ,1,22,2"
,"5,HE,XYZ,2,22,5"
,"6,SHE,WWW,2,41,0"
};
string[] tbs =
{
"1,1,39,Dispense,Ready,1"
,"2,2,39,Fill,Ready,2"
,"3,2,22,Ship,Active,0"
,"4,2,41,Del,Pending,0"
,"5,1,22,Verify,Pending,0"
};
foreach (string t in tas)
{
string[] x = t.Split(',');
DataRow row = ta.NewRow();
for (int i = 0; i < x.Length; i++) row[i] = x[i];
ta.Rows.Add(row);
}
foreach (string t in tbs)
{
string[] x = t.Split(',');
DataRow row = tb.NewRow();
for (int i = 0; i < x.Length; i++) row[i] = x[i];
tb.Rows.Add(row);
}

Merging two datatable in memory and grouping them to get sum of columns.Using linq but kind of lost here

I have two table where two column are fixed. Some columns are identical and some are new.Columns are dynamic.
Have to do it in code level and I am trying to loop and conditions
What I want is to generate a report following the condition,
All columns in table1 and table2 must be present.
If a column is common and value is there it should be added with the identical row in other table.
If any row is present in one table but not in other, it should be included.
Example data
Table1
ID | NAME | P1 | P2 | P3
----------------------------
1 | A1 | 1 | 2 | 3.3
2 | A2 | 4.4 | 5 | 6
TABLE 2
ID | NAME | P1 | P2 | P4
---------------------------
1 | A1 | 10 | 11 | 12
2 | A2 | 12 | 14 | 15
3 | A3 | 16 | 17 | 18
Expected output:
ID | NAME | P1 | P2 | P3 | P4
---------------------------------
1 | A1 | 11 | 13 | 3.3 | 12
2 | A2 | 16.4 | 19 | 6 | 15
3 | A3 | 16 | 17 | null| 18
Progress till now:
First I merged those two table in to table1
table1.Merge(table2)
Then trying to group by over it
var query = from row in table1.AsEnumerable()
group row by new
{
ID = row.Field<int>("ID"),
Name = row.Field<string>("Name")
}
into grp
select new
{
ID = grp.Key.ID,
Name = grp.Key.Name,
Phase1 = grp.Sum(r => r.Field<decimal>("P1"))
};
I have modified this code to get a datatable. Please see attached cs file.
This is working, but as the number of columns are dynamic, I guess I have to repeat it for other columns and join all these small tables where one columns will be added.
How can I merge all those small tables?
I am lost here.Is there any other way. Its feeling as stupid thing.
Any help would be appreciated.
Attached File:
http://dl.dropbox.com/u/26252340/Program.cs
You want to use an implementation of a full outer join. Something like what follows.
Some setup so you can try this yourself:
DataTable t1 = new DataTable();
t1.Columns.Add("ID", typeof(int));
t1.Columns.Add("Name", typeof(string));
t1.Columns.Add("P1", typeof(double));
t1.Columns.Add("P2", typeof(double));
t1.Columns.Add("P3", typeof(double));
DataRow dr1 = t1.NewRow();
dr1["ID"] = 1;
dr1["Name"] = "A1";
dr1["P1"] = 1;
dr1["P2"] = 2;
dr1["P3"] = 3.3;
t1.Rows.Add(dr1);
DataRow dr2 = t1.NewRow();
dr2["ID"] = 2;
dr2["Name"] = "A2";
dr2["P1"] = 4.4;
dr2["P2"] = 5;
dr2["P3"] = 6;
t1.Rows.Add(dr2);
DataTable t2 = new DataTable();
t2.Columns.Add("ID", typeof(int));
t2.Columns.Add("Name", typeof(string));
t2.Columns.Add("P1", typeof(double));
t2.Columns.Add("P2", typeof(double));
t2.Columns.Add("P4", typeof(double));
DataRow dr3 = t2.NewRow();
dr3["ID"] = 1;
dr3["Name"] = "A1";
dr3["P1"] = 10;
dr3["P2"] = 11;
dr3["P4"] = 12;
t2.Rows.Add(dr3);
DataRow dr4 = t2.NewRow();
dr4["ID"] = 2;
dr4["Name"] = "A2";
dr4["P1"] = 12;
dr4["P2"] = 14;
dr4["P4"] = 15;
t2.Rows.Add(dr4);
DataRow dr5 = t2.NewRow();
dr5["ID"] = 3;
dr5["Name"] = "A3";
dr5["P1"] = 16;
dr5["P2"] = 17;
dr5["P4"] = 18;
t2.Rows.Add(dr5);
The queries look like:
var ids = (from r1 in t1.AsEnumerable() select new { ID = r1["ID"], Name = r1["Name"] }).Union(
from r2 in t2.AsEnumerable() select new { ID = r2["ID"], Name = r2["Name"] });
var query = from id in ids
join r1 in t1.AsEnumerable() on id equals new { ID = r1["ID"], Name = r1["Name"] } into left
from r1 in left.DefaultIfEmpty()
join r2 in t2.AsEnumerable() on id equals new { ID = r2["ID"], Name = r2["Name"] } into right
from r2 in right.DefaultIfEmpty()
select new
{
ID = (r1 == null) ? r2["ID"] : r1["ID"],
Name = (r1 == null) ? r2["Name"] : r1["Name"],
P1 = (r1 == null) ? r2["P1"] : (r2["P1"] == null) ? r1["P1"] : (double)r1["P1"] + (double)r2["P1"],
P2 = (r1 == null) ? r2["P2"] : (r2["P2"] == null) ? r1["P2"] : (double)r1["P2"] + (double)r2["P2"],
P3 = (r1 == null) ? null : r1["P3"],
P4 = (r2 == null) ? null : r2["P4"]
};
Got this solved by
table1.Merge(table2, true, MissingSchemaAction.Add);
finalTable = table1.Clone();
finalTable.PrimaryKey = new DataColumn[] { finalTable.Columns["ID"], finalTable.Columns["Name"] };
List<string> columnNames = new List<string>();
for (int colIndex = 2; colIndex < finalTable.Columns.Count; colIndex++)
{
columnNames.Add(finalTable.Columns[colIndex].ColumnName);
}
foreach (string cols in columnNames)
{
var temTable = new DataTable();
temTable.Columns.Add("ID", typeof(int));
temTable.Columns.Add("Name", typeof(string));
temTable.Columns.Add(cols, typeof(decimal));
(from row in table1.AsEnumerable()
group row by new { ID = row.Field<int>("ID"), Team = row.Field<string>("Team") } into grp
orderby grp.Key.ID
select new
{
ID = grp.Key.ID,
Name = grp.Key.Team,
cols = grp.Sum(r => r.Field<decimal?>(cols)),
})
.Aggregate(temTable, (dt, r) => { dt.Rows.Add(r.ID, r.Team, r.cols); return dt; });
finalTable.Merge(temTable, false, MissingSchemaAction.Ignore);
}
Since the columns are dynamic you'll need to return an object with dynamic properties. You could do this with an ExpandoObject.
The following code is ugly in many ways - I would do some massive refactoring before letting it go - but it gets the job done and might help you out to achieve what you want.
(Sorry for using the other linq syntax.)
var query = table1.AsEnumerable()
.GroupBy(row => new
{
ID = row.Field<int>("ID"),
Name = row.Field<string>("Name")
})
.Select(grp =>
{
dynamic result = new ExpandoObject();
var dict = result as IDictionary<string, object>;
result.ID = grp.Key.ID;
result.Name = grp.Key.Name;
foreach (DataRow row in grp)
{
foreach (DataColumn column in table1.Columns)
{
string columnName = column.ColumnName;
if (columnName.Equals("ID") || columnName.Equals("Name"))
continue;
//else
if (!dict.Keys.Contains(columnName))
dict[columnName] = row[columnName];
else
{
if (row[columnName] is System.DBNull)
continue;
if (dict[columnName] is System.DBNull)
{
dict[columnName] = row[columnName];
continue;
}
//else
dict[columnName] = (decimal)dict[columnName] + (decimal)row[columnName];
}
}
}
return result;
});

Problem updating multi-row

table:ProductComapny
field:NameProduct
NameProduct
1
1
1
4
5
i want update fields NameProduct where NameProduct= 1 to(NameProduct=1,NameProduct=2,NameProduct=3
how can this work??
result
NameProduct
1
2
3
4
5
var source = new int[] {1,1,1,4,5};
var result = source.Select( (val,i) => val==1 ? i : val );
Try This:
using (DataClassesDataContext dc=new DataClassesDataContext())
{
var my = from a in dc.ProductComapny
where a.NameProduct== 1
select a;
int i=1;
foreach (var item in my)
{
item.NameProduct= i;
dc.SubmitChanges();
i++;
}
}

Categories