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"] };
Related
i have two tables suck as the one below i wanna know how to sum "calorie" column based on name from table 1 and then insert the value to table 2
table1(PK->ID(int),Name(nvarchar),amount(int),calorie(int))
table2(pk->ID(int),name(nvarchar),totalcalorie(int))
+-------+--------+----------+--------------+
| int | name | amount | calorie |
+-------+--------+----------+--------------+
| 1 | a | 10 | 20 |
| 2 | b | 5 | 20 |
| 2 | b | 10 | 10 |
| 1 | a | 10 | 10 |
| 2 | b | 15 | 35 |
| 3 | c | 20 | 15 |
+-------+--------+----------+--------------+
something like this is my first table now imagine same kinda table for table2
only this time something like :
1-------a--------30
2-------b--------65
3-------c--------15
is this possible at all? what i wrote till now and doesn't work is this :
DataClasses1DataContext db = new DataClasses1DataContext();
var q = from row in db.table1
group row by new { row.name }
into grp
select new
{
grp.Key.name,
sum = grp.Sum(row => row.calorie)
};
db.SubmitChanges();
Now you are just selecting data. You need the block for insertion like the following:
var q = (from row in db.table1
group row by new { row.id, row.name } into grp
select new
{
grp.Key.id,
grp.Key.name,
sum = grp.Sum(s => s.calorie)
}).ToList();
foreach(var item in q)
{
var e = new db.table2Entity
{
id = item.id,
name = item.name,
totalcalorie = item.sum
};
db.Table2.AddObject(e);
}
db.SaveChanges();
I think that you do not see the result on you databse after db.SubmitChanges() wright ? Linq query should work fine but Submit doesn't see the change becouse there is no change in table2. You only select data and group it from table1. Please debug and see what is in q variable.
I have two Datatables shown in below
Table 1
-------------------------
ID | Name
--------------------------
1 | JOHN
2 | GEORGE
3 | RAGU
--------------------------
Table 2
----------
ID | AGE
----------
1 | 23
2 | 23
3 | 22
----------
I just want the result as like this..
Result
-------------------------
ID | Name | AGE
--------------------------
1 | JOHN | 23
2 | GEORGE | 23
3 | RAGU | 22
--------------------------
Thanks..
you can check this out:
static void Main(string[] args)
{
Program p = new Program();
DataTable dt1= p.Get1();
DataTable dt2 = p.Get2();
DataTable dt3 = p.Get3(dt1, dt2);
}
public DataTable Get1()
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID");
dt1.Columns.Add("Name");
dt1.Rows.Add("1", "JOHN");
dt1.Rows.Add("2", "GEORGE");
dt1.Rows.Add("3", "RAGU");
return dt1;
}
public DataTable Get2()
{
DataTable dt2 = new DataTable();
dt2.Columns.Add("AGE");
dt2.Rows.Add("23");
dt2.Rows.Add("23");
dt2.Rows.Add("22");
return dt2;
}
public DataTable Get3(DataTable dt1,DataTable dt2)
{
dt1.Columns.Add("Age");
for (int i = 0; i < dt1.Rows.Count; i++)
{
dt1.Rows[i]["Age"] = dt2.Rows[i]["Age"];
}
return dt1;
}
I assume that this is what you might be looking for
INSERT INTO Result (ID, Name, Age)
SELECT T1.ID, T1.Name, T2.Age
FROM
Table1 AS T1
INNER JOIN
Table2 AS T2
ON
T1.ID = T2.ID
ORDER BY
T1.ID
Have you heard about INNER JOIN?
Basically, what you want to do is:
SELECT Persons.ID, Persons.Name, Ages.Age
FROM Persons INNER JOIN Ages ON Persons.ID = Ages.ID
Now you can insert that into another table if you want.
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.
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;
});
In the following code for finding sum of Rate column in the DataTable dt:
dt.Compute("Sum(Convert(Rate, 'System.Int32'))");
In this is it possible to assign group by clause like SQL Inn order to get Sum based on a value in another column of the same dt Fo eg:
----------------------------
Rate | Group |type
----------------------------
100 | A | 1
120 | B | 2
70 | A | 1
50 | A | 2
----------------------------
I just wanna to get.
Sum A=170(type-1) SUMA=50(type-2) an Sum B=120(type-2)
Ref: I got ans in my previous question in single column case
Group by in DataTable Column sum.
You can group by an anonymous type:
var result = from r in dt.AsEnumerable()
group r by new { Group = r["Group"], Type = r["Type"] } into g
select new { Group = g.Key.Group,
Type = g.Key.Type,
Sum = g.Sum(x => Convert.ToInt32(x["Rate"])) };
foreach (var r in result)
{
Console.WriteLine("Group {0}, Type {1}, Sum {2}", r.Group, r.Type, r.Sum);
}