Why won't two Identical DataTables show any differences? - c#

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,

Related

copy content of one DataTable to another without using clone or copy

I want to copy the content from one datatable to another without copying or cloning the data structure. what is the best way to do this?
I need to do it this way because I am given a datatable from a SQL server stored procedure and I cannot amend the given read only table. so I need recreate it without copying all the underlying structure.
I hope that makes sense.
Regards
Amarino
If you want to copy dataTable you have two options first one is copy or clone.
The second option is using foreach or for loop to copy you can get any columns from dataTable
int columnsize = dt.Columns.Count;
foreach (DataRow X in dt.Rows)
{
for (int i = 0; i < columnsize; i++)
{
// int bir = Convert.ToInt32(X[i]);
// you can set here your need dataTable
}
}
// then here new dataTable you can assing to any datagridview.DataSource = newDataTable
but in the second case you should know ahead what data will come in which place to look this you can get any cell and assing it new DataTable
here is my using code
DataTable dh1 = new DataTable("data1");
dh1.Columns.Add("specification_name", typeof(string));
dh1.Columns.Add("summalar", typeof(string));
dh1.Columns.Add("address", typeof(string));
dh1.Columns.Add("id1", typeof(int));
dh1.Columns.Add("client_id", typeof(int));
dh1.Columns.Add("stack_id", typeof(int));
foreach (DataRow dd in dt.Rows)
{
DataTable temp = new DataTable("temp");
DataRow ttt = dh1.NewRow();
for (int j = 0; j < col; j++)
{
ttt[0] = dd[1];
ttt[1] = dd[2];
ttt[2] = dd[3];
ttt[3] = dd[4];
ttt[4] = dd[5];
ttt[5] = dd[6];
break;
}
dh1.Rows.Add(ttt);
}
I was looking to do something like this: The below solution works for me.
DataTable lDT2 = someMethod(); //populated with data from SomeMethod()
DataTable lDT3 = new DataTable();
lDT3.Columns.Add("Name", typeof(string));
lDT3.Columns.Add("Name2", typeof(string));
foreach (DataColumn col in lDT2.Columns) {
lDT3.Columns.Add(col.ColumnName, col.DataType);
}
foreach (DataRow dr in lDT2.Rows) {
DataRow lDT3dr = lDT3.NewRow();
for (int i = 0; i < lDT2.Columns.Count; i++) {
if (i == 0) { lDT3dr[i] = "some info"; }
if (i == 1) { lDT3dr[i] = "more info"; }
lDT3dr[i+2] = dr[i];
}
lDT3.Rows.Add(lDT3dr);
}
If I understand correctly you want to copy the data but ignore the schema. You can do this by gathering data set from the source table then iterate through each row and insert it into the destination table.
This is a simple way to copy data from one table to another without any worry of keys or constraints. You will need to make sure your destination table can accept the data (it must be of the correct type or you must cast it to something acceptable).
Another option is to use DefaultView.ToTable(). This also allows you to pull DISTINCT values. If you want all columns
var myNewTable = ExistingDataTable.DefaultView().ToTable();
If you wanted to limit for some criteria
var dv = ExistingDataTable.DefaultView();
dv.Filter = "SomeColumn = 'SomeValue'";
var myFilteredTable = dv.ToTable();

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.

Filter RadGrid results and store into a new datatable

I have a grid that returns 8000 results, and I would like to filter these results by date and store them into a new datatable and rebind later. I receive this error:
Input array is longer than the number of columns in this table.
What are my options?
if (e.CommandName == "Filter")
{
DataTable dt = new DataTable();
foreach (GridDataItem item in RadGrid2.Items)
{
for (int i = 0; i < RadGrid2.Items.Count; i++ )
{
dt.Rows.Add(item);
}
}
if (e.CommandName == "Filter")
{
DataTable dt = new DataTable();
td.Columns.Add("Column1");
td.Columns.Add("Column2");
//etc.
//add same columns as you have in RadGrid2
foreach (GridDataItem item in RadGrid2.Items)
{
for (int i = 0; i < RadGrid2.Items.Count; i++ )
{
dt.Rows.Add(item);
}
}
You have to add columns to your DataTable td. Items cannot be added to nowhere.
Returning 8000 results to RadGrid is too much.
Please consider using AllowCustomPaging, and retrieve only the rows you need to display.
For example, using Skip and Take in Entity Framework.

Compare dataset or a better idea

How do I compare values of one data set from another.
1st dataset ["proper records"] is coming from SQL Server with column names
[id], [subsNumber]
2nd dataset ["proper and inproper records"] is coming from progress database, with different columns except 1 which is subsNumber
How do I go and make another dataset which has all the [subsNumber] from ["proper records"] with matching records from 2nd datset ["proper inproper records"] ?
or
delete all the records in 2nd dataset["proper and inproper records"] which don't match the "subsNumber" column in the 1st dataset
or any other idea
basically How do I get all records from 2nd dataset which has same "subsNumber" as the 1st dataset
The key is using System.Data.DataRelation to join your 2 datatables on a common column (or columns).
Here's some code derived from a post at KC's See Sharp Blog
public DataTable GetImproperRecords(DataTable ProperRecords, DataTable ImproperRecords) {
DataTable relatedTable = new DataTable("Difference");
try {
using (DataSet dataSet = new DataSet()) {
dataSet.Tables.AddRange(new DataTable[] { ProperRecords.Copy(), ImproperRecords.Copy() });
DataColumn properColumn = new DataColumn();
properColumn = dataSet.Tables[0].Columns[1]; // Assuming subsNumber is at index 1
DataColumn improperColumn = new DataColumn();
improperColumn = dataSet.Tables[1].Columns[0]; // Assuming subsNumber is at index 0
//Create DataRelation
DataRelation relation = new DataRelation(string.Empty, properColumn, improperColumn, false);
dataSet.Relations.Add(relation);
//Create columns for return relatedTable
for (int i = 0; i < ImproperRecords.Columns.Count; i++) {
relatedTable.Columns.Add(ImproperRecords.Columns[i].ColumnName, ImproperRecords.Columns[i].DataType);
}
relatedTable.BeginLoadData();
foreach (DataRow parentrow in dataSet.Tables[1].Rows) {
DataRow[] childrows = parentrow.GetChildRows(relation);
if (childrows != null && childrows.Length > 0)
relatedTable.LoadDataRow(parentrow.ItemArray, true);
}
relatedTable.EndLoadData();
}
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
return relatedTable;
}
I solved the problem:
1st dataset--> loop throuhg and get the subsNumber
Call function and pass subsNumber and 2nd dataset--> to it
Then start another loop for new dataset
Continue if subsnumber don't match
If subsNumber match work on that data like add columns to sqlserver table etc.
code:
foreach (DataRow row in ecommDS.Tables["EcommData"].Rows)
{
//string statCode = ""
string prdCode = ""; //declaring var for getting string format from ecomm
string checking = "";
prdCode = row["PRD-CDE"].ToString();
checking = row["SUBS-NUM"].ToString();
if(checking != subsNum)
{
continue;
}
To get all the records from 2nd dataset that match the records from the 1st dataset would be something like this:
IEnumerable list3 = list2.Where(l2=>list1.Contains(l1=>l1.subsNumber == l2.subsNumber));
Something along those lines!

Categories

Resources