Copy to Datatable - c#

I am joining datatables to create a new datatable,
Code :
var row = from r0w1 in dt_vi.AsEnumerable()
join r0w2 in dt_w.AsEnumerable()
on r0w1.Field<int>("ID") equals r0w2.Field<int>("iD")
join r0w3 in dt_re.AsEnumerable()
on r0w1.Field<int?>("ID") equals r0w3.Field<int?>("id")
join r0w4 in dt_def.AsEnumerable()
on r0w1.Field<int?>("ID") equals r0w4.Field<int?>("id") into ps
from r0w4 in ps.DefaultIfEmpty()
select r0w1.ItemArray.Concat(r0w2.ItemArray.Concat(r0w3.ItemArray.Concat(r0w4 != null ? r0w4.ItemArray : new object[] { }))).ToArray();
foreach (object[] values in row)
dt.Rows.Add(values);
In the above code,
foreach (object[] values in row)
dt.Rows.Add(values);
is slow for hundreds of thousands of rows. I want to put the data of row into dt
I want to know if there is any way exists so, that I don't have to use loop to create a new datatable ?

As #Thanos Markow mentioned, you need to use dataTable.Merge(the second data table).
An Important Note: The merge operation takes into account only the original table, and the table to be merged. Child tables are not affected or included. If a table has one or more child tables, defined as part of a relationship, each child table must be merged individually.

Related

C# SqlCommandBuilder , CommandUpdate - how to write correct update based on select with outer join tables

I want is to update 2 fields: p.FlagaWaznosci and p.Notatka
My select looks like:
Select DISTINCT p.id,p.Model_Number,p.Product_Name,p.Website_Link,p.Entry_date,p.LastUpdate_date,p.PrzydzialRozmiarow_ID,p.FlagaWaznosci,p.Notatka,pr.NazwaRozmiarowki,wd.LINK_StockX
from Products p with(nolock)
left outer join Widok_Model_Sklep_Stockx_Linki wd with(nolock) on wd.Product_ID = p.id
left outer join PrzydzialRozmiarow pr with(nolock) on pr.id = p.PrzydzialRozmiarow_ID
inner join Shops s with(nolock) on s.ID = p.Shop_ID
There is just outer joins to get correct data that I need to be displayed in gridview. And now when values p.FlagaWaznosci or p.Notatka is changed I want to save update in my database.
I try to use
//loads dataand fill to gridview
DataTable WszystkieProduktyDlaDanegoSklepu;
SqlDataAdapter sda555123 = new SqlDataAdapter("here is my select", conn123);
sda555123.Fill(WszystkieProduktyDlaDanegoSklepu);
//later update table Prooducts and save changed on p.Notatka and p.FlagaWaznosci
cmdbl = new SqlCommandBuilder(sda555123);
cmdbl.ConflictOption = ConflictOption.OverwriteChanges;
sda555123.Update(WszystkieProduktyDlaDanegoSklepu);
But this way I have error
So I searched a lot and found: I have to write own CommandUpdate.
So ... sda555123.UpdateCommand and I don't have idea how can I write own update for it in update command.
The update in SQL Server should looks like:
Update Products
set FlagaWaznosci = #Flagawaznosci from my sda555123,
Notatka = #Notatka from my sda555123
where id = # p.ID from my sda555123
How my command update should looks like here?
EDIT 1 :
i try added : WszystkieProduktyDlaDanegoSklepu.PrimaryKey = new DataColumn[] { WszystkieProduktyDlaDanegoSklepu.Columns["id"] }
but nothing . Still this error.
I would solve the problem by changing the approach instead of mutating the update command of the SqlDataAdapter.
Given that Products.id in your query is unique within the result set:
1- Create a temporary table (local or global), having its columns same as the result of the query with id as primary key.
2- Insert data into the temporary table using your select statement.
3- DataAdatper.selectQuery.commandText is set to "select * from TempTable"
4- The update command is now based on a simple select statement, consequently any change in the datagridview/datatable can be updated to the temptable using dataadapter.update(datatable)
5- As for the final database update, you could use the below statement
Update Prd
set Prd.FlagaWaznosci = TempTable.FlagaWaznosci ,Prd.Notatka = TempTable.Notatka etc.. all the fields that need to be updated
from my Products as Prd
Inner Join TempTable on TempTable.id = Prd.id
Note that the update in (5) will affect all rows, even unchanged ones.
To address this issue you can proceed as below
1- Save changed ids in a list.
List<string> lst = new List<string>();
foreach(DataRow dr in datatable.GetChanges(DataRowState.Modified))
{
lst.add(dr["id"].ToString());
}
2- Convert your list to a string value to be concatenated with the query in (5)
String strchange = String.Join(",",lst); //will give you id1,id2,...
//The update query becomes
Update Prd
set Prd.FlagaWaznosci = TempTable.FlagaWaznosci ,Prd.Notatka =
TempTable.Notatka etc.. all the fields that need to be updated
from my Products as Prd
Inner Join TempTable on TempTable.id = Prd.id
Where Prd.id In ( strchange )
Kindly update your tables separately because in join you just seen two or more than two tables into one table form . but you cant do any crud operation on

LINQ join to return dynamic column list

I'm looking for a way to return a dynamic column list from a LINQ join of two datatables.
First, this is not a duplicate. I have already studied and discarded:
C# LINQ list select columns dynamically from a joined dataset
Creating a LINQ select from multiple tables
How to do a LINQ join that behaves exactly like a physical database inner join?
(and many others)
Here is my starting point:
public static DataTable JoinDataTables(DataTable dt1, DataTable dt2, string table1KeyField, string table2KeyField, string[] columns) {
DataTable result = ( from dataRows1 in dt1.AsEnumerable()
join dataRows2 in dt2.AsEnumerable()
on dataRows1.Field<string>(table1KeyField) equals dataRows2.Field<string>(table2KeyField)
[...I NEED HELP HERE with the SELECT....]).CopyToDataTable();
return result;
}
A few notes and requirements:
There is no database engine. The data sources are large CSV files (500K+ records) being read into c# DataTables.
Because the CSVs are large, looping through each record in the join is a bad solution for performance reasons. I've already tried record looping and it's just too slow. I get great performance on the join above, but I can't find a way to have it return just the columns I want (specified by the caller) without looping records.
If I need to loop over columns in the join, that is perfectly fine, I just don't want to loop rows.
I want to be able to pass in an array of column names and return just those columns in the resulting DataTable. If both datatables being passed in happen to have a column named the same, and if that column is in my array of column names, just pass back either column because the data will be the same between the 2 columns in that case.
If I need to pass in 2 arrays (1 for each datatable's desired columns) that's fine, but 1 array of column names would be ideal.
The column list cannot be static and hardcoded into the function. The reason is because my JoinDataTables() is called from many different places in my system in order to join a wide variety of CSVs-turned-datatables, and each CSV file has very different columns.
I don't want all columns returned in the resulting DataTable -- just the columns I specify in the columns array.
So suppose, before calling JoinDataTables(), I have the following 2 datatables:
Table: T1
T1A T1B T1C T1D
==================
10 AA H1 Foo1
11 AB H1 Foo2
12 AA H2 Foo1
13 AB H2 Foo2
Table: T2
T2A T2X T2Y T2Z
==================
12 N1 O1 Yeah1
17 N2 O2 Yeah2
18 N3 O1 Yeah1
19 N4 O2 Yeah2
Now suppose we join these 2 tables like so:
ON T1.T1A = T2.T2A
select * from [join]
and that yields this resultset:
T1A T1B T1C T1D T2A T2X T2Y T2Z
====================================
12 AA H2 Foo1 12 N1 O1 Yeah1
Notice that only 1 row is yielded by the join.
Now to the crux of my question. Suppose that for a given use case, I want to return only 4 columns from this join: T1A, T1D, T2A, and T2Y. So my resultset would then look like this:
T1A T1D T2A T2Y
==================
12 Foo1 12 O1
I'd like to be able to call my JoinDataTables function like so:
DataTable dt = JoinDataTables(dt1, dt2, "T1A", "T2A", new string[] {"T1A", "T1D", "T2A", "T2Y"});
Keeping in mind performance and the fact that I don't want to loop through records (because it's slow for large sets of data), how can this be accomplished? (The join is already working well, now I just need a correct select segment (whether via new{..} or whatever you think)).
I cannot accept a solution with a hardcoded column list inside the function. I have found examples of that approach all over SO.
Any ideas?
EDIT: I'd be ok getting ALL columns back every time, but every attempt I've made to include all columns has resulted in some kind of FULL OUTER JOIN or CROSS JOIN, returning orders of magnitude more records than it should. So, I'd be open to getting all columns back, as long as I don't get the cross join.
I'm not sure of the performance with 500k records, but here is an attempted solution.
Since you are combining two subsets of DataRows from different tables, there are no easy operations that will create the subset or create a new DataTable from the subsets (though I have an extension method for flattening an IEnumerable<anon> where anon = new { DataRow1, DataRow2, ... } from a join, it would probably be slow for you).
Instead, I pre-create an answer DataTable with the columns requested and then use LINQ to build the value arrays to be added as the rows.
public static DataTable JoinDataTables(DataTable dt1, DataTable dt2, string table1KeyField, string table2KeyField, string[] columns) {
var rtnCols1 = dt1.Columns.Cast<DataColumn>().Where(dc => columns.Contains(dc.ColumnName)).ToList();
var rc1 = rtnCols1.Select(dc => dc.ColumnName).ToList();
var rtnCols2 = dt2.Columns.Cast<DataColumn>().Where(dc => columns.Contains(dc.ColumnName) && !rc1.Contains(dc.ColumnName)).ToList();
var rc2 = rtnCols2.Select(dc => dc.ColumnName).ToList();
var work = from dataRows1 in dt1.AsEnumerable()
join dataRows2 in dt2.AsEnumerable()
on dataRows1.Field<string>(table1KeyField) equals dataRows2.Field<string>(table2KeyField)
select (from c1 in rc1 select dataRows1[c1]).Concat(from c2 in rc2 select dataRows2[c2]).ToArray();
var result = new DataTable();
foreach (var rc in rtnCols1)
result.Columns.Add(rc.ColumnName, rc.DataType);
foreach (var rc in rtnCols2)
result.Columns.Add(rc.ColumnName, rc.DataType);
foreach (var rowVals in work)
result.Rows.Add(rowVals);
return result;
}
Since you were using query syntax, I did as well, but normally I would probably do the select like so:
select rc1.Select(c1 => dataRows1[c1]).Concat(rc2.Select(c2 => dataRows2[c2])).ToArray();
Updated: It is probably worthwhile to use the column ordinals instead of the names to index into each DataRow by replacing the definitions of rc1 and rc2:
var rc1 = rtnCols1.Select(dc => dc.Ordinal).ToList();
var rc1Names = rtnCols1.Select(dc => dc.ColumnName).ToHashSet();
var rtnCols2 = dt2.Columns.Cast<DataColumn>().Where(dc => columns.Contains(dc.ColumnName) && !rc1Names.Contains(dc.ColumnName)).ToList();
var rc2 = rtnCols2.Select(dc => dc.Ordinal).ToList();

Compare Data tables

I need to compare the two data table,
In both datatable we have the systemuserid . In datatable1 we have two rows.The system user id will start with c2dd... and 53cf...
Now i need to compare the two tables whther all systemuserids are available in second Datatable.
In these table the c2dd... sustem user is not available in the datatable 2. so i need to add that c2dd.. row in datatable 2 with noofCall as 0
If you have two datatable available, then you can compare two table and get table1 row systemuserid which are not available in table2 in following way :
IEnumerable<DataRow> differenceRows = table1.AsEnumerable()
.Where(x => table2.AsEnumerable()
.All(y => y.Field<string>("systemuserid") != x.Field<string>("systemuserid")));
After getting differenceRows, you can add new row in table2 iterating through differenceRows.

C# Full Outer Join Two DataTables Without LINQ

Thanks for reading this.
Here's my goal:
I have two Datatables I've read in from Excel Worksheets. The Datatables have the same schema (Columns A, B, C, ... in Datatable1 has same kind of data as Column A, B, C, ... in Datatable2).
I need to compare data in the tables by arbitrary columns (i.e. for comparison only Column A and C matter, but I need to keep data in Column A, B, C, ..., N).
Since I'm reading these in from Excel Worksheets, the schema can't be expected. For example, if I load a different set of Worksheets, the comparison columns may differ. For this reason, I can't use LINQ, which is like a hard coded SQL statement.
I need to perform the equivalent of a FULL OUTER JOIN. I'm trying to show all data, including missing data from either datatable which doesn't appear in the other datatable.
I've read a little bit about DataRelations, but I'm not sure how to use them.
Please provide example code.
Thanks in advance!
Given a pair of DataTables with an arbitrary number of columns, and given a function that can create a grouping value of a reasonable type from each of the two DataTables, you can use Linq to do most of the work for you.
Let's start with a function to extract the join key from the DataTables. It'd be nice to just return an object[], but they don't compare well. We can do it with a Tuple<object, object> however - those work nicely for this purpose. And if you need more columns you can just add more columns :P
// Produces a JoinKey as Tuple containing columns 'A' and 'C' (0 and 2)
public Tuple<object, object> GetJoinKey(DataRow row)
{
return Tuple.Create(row[0], row[2]);
}
Now the join. We can't do a full outer join directly, but we can do an outer join both ways and Union the results:
// given DataTables table1 & table2:
var outerjoin =
(
from row1 in table1.AsEnumerable()
join row2 in table2.AsEnumerable()
on GetJoinKey(row1) equals GetJoinKey(row2)
into matches
from row2 in matches.DefaultIfEmpty()
select new { key = GetJoinKey(row1), row1, row2 }
).Union(
from row2 in table2.AsEnumerable()
join row1 in table1.AsEnumerable()
on GetJoinKey(row2) equals GetJoinKey(row1)
into matches
from row1 in matches.DefaultIfEmpty()
select new { key = GetJoinKey(row2), row1, row2 }
);
Next up you have to create a suitable output format - a DataTable that has all the rows from both sources, plus a field to hold some info about the key:
DataTable result = new DataTable();
// add column for string value of key:
result.Columns.Add("__key", typeof(string));
// add columns from table1:
foreach (var col in table1.Columns.OfType<DataColumn>())
result.Columns.Add("T1_" + col.ColumnName, col.DataType);
// add columns from table2:
foreach (var col in table2.Columns.OfType<DataColumn>())
result.Columns.Add("T2_" + col.ColumnName, col.DataType);
And finally, fill the table from the query:
var row1def = new object[table1.Columns.Count];
var row2def = new object[table2.Columns.Count];
foreach (var src in outerjoin)
{
// extract values from each row where present
var data1 = (src.row1 == null ? row1def : src.row1.ItemArray);
var data2 = (src.row2 == null ? row2def : src.row2.ItemArray);
// create row with key string and row values
result.Rows.Add(new object[] { src.key.ToString() }.Concat(data1).Concat(data2).ToArray());
}
Of course we could short out a couple of those operations to get a single Linq query that does 99% of the work for us. I'll leave that to you to play with if it sounds like fun.
Here's the full method, done as an extension with a generic function for the join key generator, making it reasonably generic:
public static DataTable FullOuterJoin<T>(this DataTable table1, DataTable table2, Func<DataRow, T> keygen)
{
// perform inital outer join operation
var outerjoin =
(
from row1 in table1.AsEnumerable()
join row2 in table2.AsEnumerable()
on keygen(row1) equals keygen(row2)
into matches
from row2 in matches.DefaultIfEmpty()
select new { key = keygen(row1), row1, row2 }
).Union(
from row2 in table2.AsEnumerable()
join row1 in table1.AsEnumerable()
on keygen(row2) equals keygen(row1)
into matches
from row1 in matches.DefaultIfEmpty()
select new { key = keygen(row2), row1, row2 }
);
// Create result table
DataTable result = new DataTable();
result.Columns.Add("__key", typeof(string));
foreach (var col in table1.Columns.OfType<DataColumn>())
result.Columns.Add("T1_" + col.ColumnName, col.DataType);
foreach (var col in table2.Columns.OfType<DataColumn>())
result.Columns.Add("T2_" + col.ColumnName, col.DataType);
// fill table from join query
var row1def = new object[table1.Columns.Count];
var row2def = new object[table2.Columns.Count];
foreach (var src in outerjoin)
{
// extract values from each row where present
var data1 = (src.row1 == null ? row1def : src.row1.ItemArray);
var data2 = (src.row2 == null ? row2def : src.row2.ItemArray);
// create row with key string and row values
result.Rows.Add(new object[] { src.key.ToString() }.Concat(data1).Concat(data2).ToArray());
}
return result;
}
Now, IF the tables have the same schema (which the above doesn't care about), you can do almost exactly the same thing - modify the result table generation to just clone one of the tables, then add some merge logic in the load loop.
Here's a Gist of the above with testing and verification that it's doing what it says. Drop that in your compiler and see what you get out.

How to join datatables of a dataset?

I have a dataset which have four datatables.
Table[0] contains columns such as: storedProcedure,DLLMethod,BLLMethod
Table[1] contains columns such as: DLLMethod,BLLMethod
Table[2] contains columns such as: UCName,BLLMethod
Table[3] contains columns such as: UCName,Function,Module
Table[4] contains columns such as: StoredProcedure,Function,Module
I want to join first four tables such that final table must contain StoredProcedure,Function and Module.Can anyone Please help me with C# coding?
LINQ to DataSet
dim query = from a in table1 join b in table2 on a.table2ID = b.ID select a,b
this can grow on many more tables by adding more joins
var query = from a in table1 join b in table2 on a.table2ID = b.ID select a,b;

Categories

Resources