DataTable Join or Merge - c#

I have 3 Data tables populated with a dataset and table adapters/ binding sources and i need to run a Join query or find another way to get specific data. (the dataset contains each table listed)
Tables:
Product Table:
Prod_ID Name
1 tv
2 couch
Consumer Table:
Con_Id Name City
----------------------
1 Gray New York
2 Joe Chicago
3 Steve Madison
Transactions Table
Tran_Id Con_ID Prod_ID Price
-------------------------------------
1 2 1 900
2 1 2 300
Given a product name i need to populate a table with each distinct city and how much that product has sold for in that city (add all prices for that product to any consumer in a given city)
I am really stumped and cant find a way. (i have tried alot)
Please help and thank you!
Nudiers approach so far:
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
DataColumn table3Column = null;
table1Column = tlobergeDataSet.Tb_Product.Columns[0];
table2Column = tlobergeDataSet.Tb_Transactions.Columns[3];
table3Column = tlobergeDataSet.Tb_Consumer.Columns[0];
relation = new DataRelation("relation", table1Column, table2Column);
tlobergeDataSet.Relations.Add(relation);

public DataTable MergeTables(DataTable dtFirst, DataTable dtSecond, string CommonColumn)
{
DataTable dtResults = dtFirst.Clone();
int count = 0;
for (int i = 0; i < dtSecond.Columns.Count; i++)
{
if (!dtFirst.Columns.Contains(dtSecond.Columns[i].ColumnName))
{
dtResults.Columns.Add(dtSecond.Columns[i].ColumnName, dtSecond.Columns[i].DataType);
count++;
}
}
DataColumn[] columns = new DataColumn[count];
int j = 0;
for (int i = 0; i < dtSecond.Columns.Count; i++)
{
if (!dtFirst.Columns.Contains(dtSecond.Columns[i].ColumnName))
{
columns[j++] = new DataColumn(dtSecond.Columns[i].ColumnName, dtSecond.Columns[i].DataType);
}
}
dtResults.BeginLoadData();
foreach (DataRow dr in dtFirst.Rows)
{
dtResults.Rows.Add(dr.ItemArray);
}
foreach (DataRow dr in dtSecond.Rows)
{
foreach (DataRow dr1 in dtResults.Rows)
{
if (dr1[CommonColumn].ToString().Equals(dr[CommonColumn].ToString()))
{
foreach (DataColumn c in columns)
{
dr1[c.ColumnName] = dr[c.ColumnName];
}
}
}
}
dtResults.EndLoadData();
return dtResults;
}

try with this.
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
//retrieve column
table1Column = ds.Tables("Table1").Columns(0);
table2Column = ds.Tables("table2").Columns(0);
//relating tables
relation = new DataRelation("relation", table1Column, table2Column);
//assign relation to dataset
ds.Relations.Add(relation);

You can only relate two tables in a DataRelation object and to access the data from
the dataset is straightforward because the data has been already related.
DataRelation relation = null;
DataColumn table1Column = null;
DataColumn table2Column = null;
DataColumn table3Column = null;
table1Column = tlobergeDataSet.Tb_Product.Columns[0];
table2Column = tlobergeDataSet.Tb_Transactions.Columns[2];
table2Column1 = tlobergeDataSet.Tb_Transactions.Columns[1];
table3Column = tlobergeDataSet.Tb_Consumer.Columns[0];
relation = new DataRelation("relation", table1Column, table2Column);
tlobergeDataSet.Relations.Add(relation);
relation = new DataRelation("relation1", table3Column , table2Column1);
tlobergeDataSet.Relations.Add(relation);

In LINQ, you can join the tables to find the data you want with syntax like so:
from a in keyTable
join b in anotherTable on a.Key equals b.Key
join c in aThirdTable on a.Key equals c.Key
select new
{
// Anonymous Object Properties using identifier a, b, and c to get data
};
You should be able to take that snippet and generate a linq query that will generate an anonymous object containing the specific data representation that you need.

Related

How to merge two datatables in c# (without any common identifier)?8

I am trying to merge two data table dt and dt4. I want to merge 2 data tables, having different schemas, and no common identifier together. Becuase the first data table dt contains some values.I get dt count on x. Based on that count I have to fetch some value table and stored in dt4. if if dt contains 3 row value then x=3 and dt4 contains 3 values. After these process I have to merge dt and dt4 and displayed as one table.
While using the given below code getting one error. The error is : "'column' argument cannot be null." Help me to find a proper soluion. Thank you.
Code:
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[x+1]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == y)
{
i = 0;
}
}
DataTable dt4 = new DataTable();
dt4.Columns.Add("Team");
foreach (string s in strArr)
{
dt4.Rows.Add(s); // Converting string array strArr[] to data table dt4
}
dt.Merge(dt4); // error poppup here. Error : 'column' argument cannot be null.
GridView2.DataSource = dt;
GridView2.DataBind();
}
dt contain
State District SiteID SiteName
----- -------- ------ --------
Sate1 District1 1001 A
Sate2 District2 1002 B
Sate3 District3 1003 C
dt4 contain
Team
-----
Team1
Team2
Team3
I need a final output as:
State District SiteID SiteName Team
----- -------- ------ -------- -----
Sate1 District1 1001 A Team1
Sate2 District2 1002 B Team2
Sate3 District3 1003 C Team3
Do you have relationship. If you have primary key ID in First Table and you can add ID column in Second Table
See here MSDN Article Merge Datatables
If you add a relationship between the 2 datatables, like a common identifier - you would be able to extract the common columns between datatables automatically using Linq.
Something like the following;
var commonColumns = dt1.Columns.OfType<DataColumn>().Intersect(dt2.Columns.OfType<DataColumn>(), new DataColumnComparer());
DataTable result = new DataTable();
dt1.PrimaryKey = commonColumns.ToArray();
result.Merge(dt1, false, MissingSchemaAction.AddWithKey);
result.Merge(dt2, false, MissingSchemaAction.AddWithKey);
Have a look at a previous question about this Full outer join, on 2 data tables, with a list of columns
The given code is working perfectly. Thank you for all valuable comments.
Code :
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[x+1]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == y)
{
i = 0;
}
}
DataTable dt4 = new DataTable();
dt4.Columns.Add("Team");
foreach (string s in strArr)
{
dt4.Rows.Add(s); // Converting string array strArr[] to data table dt4
}
//Adding new data table for merging two table details
DataTable dt7 = new DataTable();
//create columns and copy data from dt:
dt7 = dt.Copy();
foreach (DataColumn column in dt4.Columns)
dt7.Columns.Add(column.ColumnName, typeof(string));
//copy data from dt4:
foreach (DataRow row in dt4.Rows)
{
dt7.Rows[dt4.Rows.IndexOf(row)][5] = row[0];
}
GridView3.DataSource = dt7;
GridView3.DataBind();
}
You don't have relationship with table dt and table dt4.
Problem::You are facing this error because you dont have any relation between these two data tables.
I think you better start by adding relationship first. If you have primary key ID in dt and you can add ID column in dt4 with the relevant ID.
So first create a column in both tables which is common and then on basis of that relationship
you can use DataTable.Merge method directly

How to compare two DataTable with different number of columns?

If I want to compare two datatables and get the difference in new datatable but I want to keep an uncompared column.
example:
first Datatable
Name | Number
---- |-------
Jude | 12
Mark | 14
Bin | 15
second Datatable
Name
------
Jude
Robin
Kamil
the Datatable must have:
Name | Number
-------|----------
Mark | 14
Bin | 15
I have this method which can compare the two datatables and get the difference, but how can I get the number.
public static DataTable CompareTables(DataTable first, DataTable second)
{
first.TableName = "FirstTable";
second.TableName = "SecondTable";
//Create Empty Table
DataTable table = new DataTable("Difference");
try
{
//Must use a Dataset to make use of a DataRelation object
using (DataSet ds = new DataSet())
{
//Add tables
ds.Tables.AddRange(new DataTable[] { first.Copy(), second.Copy() });
//Get Columns for DataRelation
DataColumn[] firstcolumns = new DataColumn[1];
firstcolumns[0] = ds.Tables[0].Columns[0];
DataColumn[] secondcolumns = new DataColumn[1];
secondcolumns[0] = ds.Tables[1].Columns[0];
//Create DataRelation
DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
ds.Relations.Add(r);
//Create columns for return table
for (int i = 0; i < first.Columns.Count; i++)
{
table.Columns.Add(first.Columns[i].ColumnName, first.Columns[i].DataType);
}
//If First Row not in Second, Add to return table.
table.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r);
if (childrows == null || childrows.Length == 0)
table.LoadDataRow(parentrow.ItemArray, true);
}
table.EndLoadData();
}
}
catch (Exception ex)
{
}
return table;
}
Let the database handle these things:
SELECT name, number from table1 where name not in (select name from table2);
public static DataTable CompareTables(DataTable first, DataTable second)
{
second.PrimaryKey = new DataColumn[] {second.Columns["Name"]};
DataTable difference = second.Clone();
foreach (DataRow row in first.Rows) {
if (second.Rows.Find(row["Name"]) == null)
{
difference.ImportRow(row);
}
}
return difference;
}
#user3527065 your code will throw an argument exception as the no. of columns has to be same .
DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
I your case firstcolumns has 2 columns whereas second columns has 1 column so it would throw an argument exception.

Why won't two Identical DataTables show any differences?

I am using DataRelation to compare two DataTable and return a third table containing the rows that are not share by both original tables by using this tutorial. Below is the code.
public static DataTable Difference(DataTable First, DataTable Second)
{
//Create Empty Table
DataTable table = new DataTable("Difference");
//Must use a Dataset to make use of a DataRelation object
using(DataSet ds = new DataSet())
{
//Add tables
ds.Tables.AddRange(new DataTable[]{First.Copy(),Second.Copy()});
//Get Columns for DataRelation
DataColumn[] firstcolumns = new DataColumn[ds.Tables[0].Columns.Count];
for(int i = 0; i < firstcolumns.Length; i++)
{
firstcolumns[i] = ds.Tables[0].Columns[i];
}
DataColumn[] secondcolumns = new DataColumn[ds.Tables[1].Columns.Count];
for(int i = 0; i < secondcolumns.Length; i++)
{
secondcolumns[i] = ds.Tables[1].Columns[i];
}
//Create DataRelation
DataRelation r = new DataRelation(string.Empty,firstcolumns,secondcolumns,false);
ds.Relations.Add(r);
//Create columns for return table
for(int i = 0; i < First.Columns.Count; i++)
{
table.Columns.Add(First.Columns[i].ColumnName, First.Columns[i].DataType);
}
//If First Row not in Second, Add to return table.
table.BeginLoadData();
foreach(DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r);
if(childrows == null || childrows.Length == 0)
table.LoadDataRow(parentrow.ItemArray,true);
}
table.EndLoadData();
}
return table;
}
Surprisingly enough when I exercised this code, it only worked on few cases and failed in others.
There was one case, I was comparing two identical table (but has different source) that both has:
Same Column Name & DataType
Same Number of Rows & Columns
Same Value in Each Cells
Only to have a brand new table returned that actually has the exact same composition as the two original tables!
What did I possibly miss?
Is it possible that two identical tables (sharing features I mentioned above) can have other different properties (which doesn't seem visible to users' eyes)?
Or is it possible that this is actually a bad method? What are the possible alternatives?
EDITED
Both tables have same primitive datatype such as: System.String, System.Int32, System.DateTime
These code doesn't work on all samples I tested
Here is a print screen of 1 sample (using DataSet Visualizer)
I had to write something similar once and this is the approach I used:
First this approach only works if you don't have duplicate rows in each table.
Using primary keys..
First.PrimaryKey = firstcolumns;
Second.PrimaryKey = secondcolumns; //These throw exceptions when you have duplicate rows
Then..
foreach (DataRow dr in Second.Rows)
{
List<Object> l = new List<Object>();
foreach (DataColumn dc in secondcolumns) l.Add(dr[dc]);
if (First.Rows.Find(l.ToArray()) == null) //NOT FOUND
{
table.Rows.Add(l.ToArray());
}
}
foreach (DataRow dr in First.Rows)
{
List<Object> l = new List<Object>();
foreach (DataColumn dc in firstcolumns) l.Add(dr[dc]);
if (Second.Rows.Find(l.ToArray()) == null) //NOT FOUND
{
table.Rows.Add(l.ToArray());
}
}
Cheers,

Get distinct items from DataTable using LINQ

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()

Join Datatables from a loop and merge in one Dataset

I have this requirement that the user request one or more partnumbers.And i need to display all the result in one Data Set
Ex: Request SerialNumbers with
PartNumber Required Quantity
A 2
B 1
C 3
Code:
//Loop Request
foreach (DataRow a in request.Rows)
{
//select top(Quantity) SerialNumber,PartNumber where PartNumber=#PartNumber
var dt = new DataTable();
}
//1. PartNumber A
SerialNumber Partnumber
1 A
2 A
+
//2. PartNumber B
SerialNumber Partnumber
1 B
//3. PartNumber C
SerialNumber Partnumber
1 C
2 C
3 C
//Load to DataSet
And the result will be something like:
SerialNumber Partnumber
1 A
2 A
1 B
1 C
2 C
3 C
Thanks in Regards
I am not sure what two tables you wish to join here and on what key but regadless of that, the simplest way will be to use LINQ to Dataset. For example,
var query = from a in table1
join
b in table2
on
a.FkColumn = b.PKColumn select a,b;
Please check below logic:
DataTable myDataTable = new DataTable();
DataColumn PartNumber = new DataColumn("PartNumber");
DataColumn RequiredQuantity = new DataColumn("RequiredQuantity");
myDataTable.Columns.Add(PartNumber);
myDataTable.Columns.Add(RequiredQuantity);
DataRow dataRowPN1 = myDataTable.NewRow();
DataRow dataRowPN2 = myDataTable.NewRow();
DataRow dataRowPN3 = myDataTable.NewRow();
dataRowPN1["PartNumber"] = "A";
dataRowPN2["PartNumber"] = "B";
dataRowPN3["PartNumber"] = "C";
dataRowPN1["RequiredQuantity"] = "2";
dataRowPN2["RequiredQuantity"] = "1";
dataRowPN3["RequiredQuantity"] = "3";
myDataTable.Rows.Add(dataRowPN1);
myDataTable.Rows.Add(dataRowPN2);
myDataTable.Rows.Add(dataRowPN3);
int i = myDataTable.Rows.Count;
DataTable joinDataTable = new DataTable();
DataColumn SerialNumber = new DataColumn("SerialNumber");
DataColumn JoinPartNumber = new DataColumn("PartNumber");
joinDataTable.Columns.Add(SerialNumber);
joinDataTable.Columns.Add(JoinPartNumber);
foreach (DataRow dr in myDataTable.Rows)
{
for (int count = 1; count <= Convert.ToInt16(dr["RequiredQuantity"]); count++)
{
DataRow joindataRow = joinDataTable.NewRow();
joindataRow["SerialNumber"] = count.ToString().Trim();
joindataRow["PartNumber"] = dr["PartNumber"].ToString().Trim();
joinDataTable.Rows.Add(joindataRow);
}
}
Response.Write(joinDataTable.Rows.Count);

Categories

Resources