getting non matched values from two Datatable - c#

Is there any direct method for getting non matched values from two data table. I have one datatable which returns all the groups from Active Directory, and another datatable consist of all the group names from sharepoint list. But i need the non matched values by comparing these two datatables. please help me, if it possible.
Thanks in advance.

You could use DataRowComparer to compare the rows.
For instance, to compare the first rows of 2 data tables:
DataRow left = table1.Rows[0];
DataRow right = table2.Rows[0];
IEqualityComparer<DataRow> comparer = DataRowComparer.Default;
bool bEqual = comparer.Equals(left, right);

You can use .Except to do this. (Assuming an ID column)
IEnumerable<int> idsInDataTableA = dataTableA.AsEnumerable().Select(row => (int)row["ID"]);
IEnumerable<int> idsInDataTableB = dataTableB.AsEnumerable().Select(row => (int)row["ID"]);
IEnumerable<int> difference = idsInDataTableA.Except(idsInDataTableB );

I want compare DataTable1 that not exist in DataTable2
You can use Linq. Very efficient approaches are Enumerable.Except or Enumerable.Join(as LEFT OUTER JOIN) which are using sets:
var keyColRows = dt1.AsEnumerable()
.Select(r => r.Field<int>("KeyColumn")
.Except(dt2.AsEnumerable().Select(r2 => r2.Field<int>("KeyColumn"));
foreach(int inTable2Missing)
Console.WriteLine(inTable2Missing);
or the Join approach selecting the whole DataRow:
var rowsOnlyInDT1 = from r1 in dt1.AsEnumerable()
join r2 in dt2.AsEnumerable()
on r1.Field<int>("KeyColumn") equals r2.Field<int>("KeyColumn") into groupJoin
from subRow in groupJoin.DefaultIfEmpty()
where subRow == null
select r1;
Here you can use rowsOnlyInDT1.CopyToDataTable to create a new DataTable of the rows in table1 which are unique/new or use foreach to enumerate them.

Related

Left join two datatable on multiple columns LINQ

How to do left join 2 DataTables based on multiple columns match ?
In order to compare what datarows is not matching in the right table
Part of incremental upload need to bring in just the new rows from source Datatable
Found a way to use LINQ to do the comparison of two datatables in c# using join (LEFT)
IEnumerable<DataRow> result = (from srcDt in dtSource.AsEnumerable()
join dstDt in dtDestination.AsEnumerable()
on new { EmployeeID = srcDt["EmployeeID "], Environment = srcDt["Environment"] } equals new { EmployeeID = dstDt["EmployeeID "], Environment = dstDt["Environment"] }
into g
from row in g.DefaultIfEmpty()
where row == null
select srcDt);
// verify if the result has any rows in the dataset
if (result.Any())
{
DataTable dtInserts = result.CopyToDataTable();
// other code which uses the new datarows to perform inserts
}

C# Linq Table query to count the non-matching entries

I am quite new to this, I am running two SQL queries and I am creating two separate data tables, DataTable1 and DataTable2.
I am applying some linq criteria to DataTable1 and creating another data table from that, which is DataTable3.
var Query3 = from table1 in DataTable1.AsEnumerable()
where table1.Field<DateTime>("DateTime") <= Yday
where table1.Field<string>("StockCode").Contains("-CA") && !(table1.Field<string>("StockCode").Contains("-CAB")) ||
table1.Field<string>("StockCode").Contains("-CM") ||
table1.Field<string>("StockCode").Contains("-LP")
select table1;
DataTable DataTable3 = Query3.CopyToDataTable()
Now I would write another query to do the following.
Both data tables have a column JobNumber. I would like to query DataTable3 in DataTable 2 to count the rows that have similar JobNumber entries. Below is what I am doing but I am not getting the correct count.
int count = (from table3 in DataTable3.AsEnumerable()
join table2 in DataTable2.AsEnumerable() on table2.Field<string>("JobNumber") equals table3.Field<string>("JobNumber")
where table2.Field<string>("JobNumber") == table3.Field<string>("JobNumber")
select table2).Count();
You are creating a cartesian join and counting its result, was that what you indented ? Also in your linq your Join expression and where expression is same (where is redundant). It is not clear what you really want to count. Probably you instead wanted to count those in DataTable2 where JobNumbers exists in DataTable3?:
var jobNumbers = (from r in DataTable3.AsEnumerable()
select r.Field<string>("JobNumber")).ToList();
var count = (from r in DataTable2.AsEnumerable()
where jobNumbers.Contains( r.Field<string>("JobNumber") )
select r).Count();
As a side note, it would be much easier if you used Linq To SQL instead (rather than Linq To DataSet).

Linq return distinct values from table if not exist in another

I am trying to return all distinct rows from Staging below where Staging.CenterCode does not exist in Centers.CenterCode.
At the moment Stagings has around 850 distinct CenterCodes and Centers is empty so I should be getting all of the distinct rows, but count begs to differ :)
Any ideas?
var query =
(from s in db.Stagings
join t in db.Centers on s.CenterCode equals t.CenterCode into tj
from t in tj.DefaultIfEmpty()
where s.CenterCode != t.CenterCode
select s.CenterCode).Distinct();
var c = query.Count();
I only need the unique columns from staging so not sure if I actually need a join with the above as I am not ever using data returned from Centers - I have however tried both and get the same 0 value for count.
Any ideas?
I would not use a join, but use a Contains.
var centerCodesQuery = db.Centers.CenterCode
.Select(x => x.CenterCode);
var query = db.Staging
.Where(x => !centerCodesQuery.Contains(x.CenterCode))
.Select(x => x.CenterCode)
.Distinct();
var c = query.Count();
the join is an inner join. So, if none of the rows in 1 table match the other table on the specified identifier then it will return 0. In yours you are trying to join 1 table with 850 distinct rows with an empty table. This will return 0.
If you actually want to return only those rows in 1 table that aren't in another you can use Except:
var query = (from s in db.Stagings
select s.CenterCode)
.Except(from t in db.Centers
select t.CenterCode);
var c = query.Count();
Looks like you are trying to implement antijoin via left outer join, which is one of the possible ways, but in order to make it work, you need to change
where s.CenterCode != t.CenterCode
to
where t == null

DataTable Join using LINQ in C#

I am joining two data tables using LINQ this way:
DataTable targetTable = dataTable1.Clone();
var dt2Columns = dataTable2.Columns.OfType<DataColumn>().Select(dc =>
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping));
var dt2FinalColumns = from dc in dt2Columns.AsEnumerable()
where targetTable.Columns.Contains(dc.ColumnName) == false
select dc;
targetTable.Columns.AddRange(dt2FinalColumns.ToArray());
var rowData = from row1 in dataTable1.AsEnumerable()
join row2 in dataTable2.AsEnumerable()
on row1.Field<string>("keyCol") equals row2.Field<string>("keyCol")
select row1.ItemArray.Concat(row2.ItemArray.Where(r2 => row1.ItemArray.Contains(r2) == false)).ToArray();
foreach (object[] values in rowData)
targetTable.Rows.Add(values);
I am facing three issues here:
In case of row count is not same for two tables, I want to pass default value or assign empty string for values not found in other table. How do I achieve this ?
If I have multiple columns and need to compare with AND how is that possible ?
What if I have to join multiple tables in run time. Is there any way to generate dynamic LINQ ?
If both tables have the same primary-key DataTable.Merge will work:
dataTable1.Merge(dataTable2 ,false, MissingSchemaAction.Add);
This will merge the schema(columns) of both tables, joins rows which have the same primary-key and add the other rows.

Filter a DataTable where the table does not contain items in List<string>

I am having a few problems quering a DataSet.Tables[0] and removing rows that do not meet the critira of a List.
//This is my list
var values = new List<string> {"Test", "Test2"};
// Now I just query the DataSet for anything that doesnt match this list
var query = from x in ds.Tables[0].AsEnumerable()
from b in values
where !x.Field<string>("ColumnName").Contains(b)
select x;
This works and returns the results but it is returning 2 x sets of the same rows (I assume because there is no join).
How can I just get Distinct values of these rows?
It sounds like you probably want:
var query = from x in ds.Tables[0].AsEnumerable()
where !values.Any(b => x.Field<string>("ColumnName").Contains(b))
select x;
In other words, find all the rows where the "ColumnName" field value isn't present in any of the values in values.
Maybe what you are looking for are the Distinct or the Intersect methods instead of ".Contains" ?
You don't have to join with your values list:
var query = from x in ds.Tables[0].AsEnumerable()
where !values.Any(str => x.Field<string>("ColumnName").Contains(str))
select x;

Categories