If I have 2 DataTables (dtOne and dtTwo) and I want to merge them and put them in another DataTable (dtAll). How can I do this in C#? I tried the Merge statement on the datatable, but this returns void. Does Merge preserve the data? For example, if I do:
dtOne.Merge(dtTwo);
Does dtOne change or does dtTwo change and if either one changes, do the changes preserve?
I know I can't do this because Merge returns void, but I want to be able to store the Merger of both dtOne and dtTwo in dtAll:
//Will Not work, How do I do this
dtAll = dtOne.Merge(dtTwo);
The Merge method takes the values from the second table and merges them in with the first table, so the first will now hold the values from both.
If you want to preserve both of the original tables, you could copy the original first, then merge:
dtAll = dtOne.Copy();
dtAll.Merge(dtTwo);
Instead of dtAll = dtOne.Copy(); in Jeromy Irvine's answer you can start with an empty DataTable and merge one-by-one iteratively:
dtAll = new DataTable();
...
dtAll.Merge(dtOne);
dtAll.Merge(dtTwo);
dtAll.Merge(dtThree);
...
and so on.
This technique is useful in a loop where you want to iteratively merge data tables:
DataTable dtAllItems = new DataTable();
foreach(var item in items)
{
DataTable dtItem = getDataTable(item); // some function that returns a data table
dtAllItems.Merge(dtItem);
}
dtAll = dtOne.Copy();
dtAll.Merge(dtTwo,true);
The parameter TRUE preserve the changes.
For more details refer to MSDN.
DataTable dtAll = new DataTable();
DataTable dt= new DataTable();
foreach (int id in lst)
{
dt.Merge(GetDataTableByID(id)); // Get Data Methode return DataTable
}
dtAll = dt;
This is what i did for merging two datatables and bind the final result to the gridview
DataTable dtTemp=new DataTable();
for (int k = 0; k < GridView2.Rows.Count; k++)
{
string roomno = GridView2.Rows[k].Cells[1].Text;
DataTable dtx = GetRoomDetails(chk, roomno, out msg);
if (dtx.Rows.Count > 0)
{
dtTemp.Merge(dtx);
dtTemp.AcceptChanges();
}
}
Related
I have a requirement where I need to copy the existing DataTable rows/values to the new DataTable,
New DataTable is of custom(different column names) structure/schema as we need this new DataTable data to be exported to Excel file later.
To copy the required column values to the new DataTable I have created string Array which contains required column names(columns from which we need to copy data to new DataTable) of existing DataTable, given below.
string[] selectedColumns = new[] { "SUPPLIER_NAME", "SUPPLIER_NO", "CONFIRMATION_NO", "RELEASE_NO", "WCO_INVOICE_NO",
"CUSTOMER_BILLED", "BALANCE_TOBILL", "SUPP_INVOICE_NO", "SUPPLIER_PAID", "BALANCE_COST" }; //TODO Add columns "WCO_INVOICE_DATE", "SUPPLIER_INVOICE_DATE" later.
For getting the required DataTable, I have created a method which will be called like below by passing existing DataTable and selected columns of existing DataTable column names as an parameters.
DataTable _dtPrjLedgerExportData = ControllerClass.dtProjectLedgerExport(dtfilter, selectedColumns);
ControllerClass Class dtProjectLedgerExport method will return the newly created DataTable i.e. DataTable with the customize Column names and the values pulled from existing DatTable,
New DataTable additionally contain two new columns (WCO_Invoice_Date, Supplier_Invoice_Date) with default blank values (set from the code).
public static DataTable dtProjectLedgerExport(DataTable dtToExport, string[] selectedColumns)
{
DataTable dt = new DataTable();
dt.Columns.Add("Supplier");
dt.Columns.Add("Supplier_No");
dt.Columns.Add("Confirmation_Number");
dt.Columns.Add("Release_Number");
dt.Columns.Add("WCO_Invoice_No");
dt.Columns.Add("WCO_Invoice_Date");
dt.Columns.Add("Customer_Billed_Amt");
dt.Columns.Add("Balance_Remaining_to_Bill");
dt.Columns.Add("Supplier_Invoice_Number");
dt.Columns.Add("Supplier_Invoice_Date");
dt.Columns.Add("Supplier_Paid_Amt");
dt.Columns.Add("Remaining_Cost_Dollar_Balance");
//temporarily set default value for non-existing rows
dt.Columns["WCO_Invoice_Date"].DefaultValue = string.Empty;
dt.Columns["Supplier_Invoice_Date"].DefaultValue = string.Empty;
//Copy rows to dt
if (dtToExport != null && dtToExport.Rows.Count > 0)
dt = new DataView(dtToExport).ToTable(false, selectedColumns);
return dt;
}
Problem:
The above code is not working as expected it is returning Data of existing DataTable with the same structure.
What changes are required in above code to get the expected result?
I'd use this approach:
public static DataTable DtProjectLedgerExport(DataTable dtToExport, string[] selectedColumns, params string[] additionalColumns)
{
DataTable dt = dtToExport.Copy(); // add columns and data
List<DataColumn> removeColumns = dt.Columns.Cast<DataColumn>()
.Where(c => !selectedColumns.Contains(c.ColumnName, StringComparer.InvariantCultureIgnoreCase))
.ToList();
removeColumns.ForEach(dt.Columns.Remove);
foreach (string colName in additionalColumns)
{
DataColumn newColumn = new DataColumn(colName);
newColumn.DefaultValue = string.Empty;
dt.Columns.Add(newColumn);
}
return dt;
}
After stating in the comments that you have different column names in each table...(Seriously that's a critical piece of information lol)! The only way is to basiaclly map the values yourself for each column like so.
public static DataTable dtProjectLedgerExport(DataTable dtToExport)
{
DataTable dt = new DataTable();
dt.Columns.Add("Supplier");
dt.Columns.Add("Supplier_No");
dt.Columns.Add("Confirmation_Number");
dt.Columns.Add("Release_Number");
dt.Columns.Add("WCO_Invoice_No");
dt.Columns.Add("WCO_Invoice_Date");
dt.Columns.Add("Customer_Billed_Amt");
dt.Columns.Add("Balance_Remaining_to_Bill");
dt.Columns.Add("Supplier_Invoice_Number");
dt.Columns.Add("Supplier_Invoice_Date");
dt.Columns.Add("Supplier_Paid_Amt");
dt.Columns.Add("Remaining_Cost_Dollar_Balance");
foreach (var expRow in dtToExport.Rows)
{
var row = dt.NewRow();
row["Supplier"] = expRow["Supplier_Name"];
//repeat for all columns you want.
dt.Rows.Add(row);
}
return dt;
}
Well, of course, because you finally override dt completely. You should enumerate the rows in dtToExport in a loop and create new rows in dt and assign the values for every field you need.
I have created a datatable which has some records, now what I want is to copy the record of first datatable to another datatable.
I tried like below:
Session["AmountData"] = AmountDatatable; // 1st datatable which has data
DataTable CompanyWiseRecord = new DataTable();
for (int i = 0; i < AmountDatatable.Rows.Count; i++)
{
CompanyWiseRecord.ImportRow(AmountDatatable.Rows[i]); // 2nd datatable which does not have data
}
Kindly let me know where I am going wrong.
You directly use session Like:
DataTable CompanyWiseRecord = (DataTable)Session["AmountData"]; //Retrieving DataTable from Session.
if you are not fetching data from table one based on some condition or assign particular rows or columns then You can do it simply by using
DataTable CompanyWiseRecord=AmountDatatable;
I have two datatables in my ASP.NET application that are filled from csv files and I am trying to combine the two into one.
Heres what the interface looks like:
When I click the 'Merge Data' button it should merge the test1.csv and test2.csv which kind of works but looks like this:
So my question is how do I align these two datatables so that all the data is on the same row?
Below is the code for the Merge Data Button:
List<string> filepaths = new List<string>();
List<DataTable> allTables = new List<DataTable>();
DataTable mergedTables = new DataTable();
int rowCount = grdFiles.Rows.Count;
for (int i = 0; i < rowCount; i++)
{
string filename = grdFiles.Rows[i].Cells[0].Text;
filepaths.Add(Server.MapPath("~/Uploads/") + filename);
}
foreach(string path in filepaths)
{
DataTable dt = new DataTable();
//converts csv into datatable
dt = GetDataTableFromCsv(path, true);
//add table to list of tables
allTables.Add(dt);
}
foreach(DataTable datatable in allTables)
{
//Merge each table in the list to the mergedTables datatable
mergedTables.Merge(datatable);
}
csvUploadResults.DataSource = mergedTables;
csvUploadResults.DataBind();
Thanks in advance for any help :)
If your objective is just to merge data without considering the relationship between the two data then you can add two more columns into first datatable and through loop get data from second table and assign them to first datatable columns. The way the data is received will be the way data will be saved in first datatable.
public DataTable MergeData(DataTable dtFirst,DataTable dtSecond)
{
dtFirst.Columns.Add("LocalAuthority");
dtFirst.Columns.Add("AverageSpeed");
for (int i = 0; i < dtFirst.Rows.Count; i++)
{
dtFirst.Rows[i]["LocalAuthority"] = dtSecond.Rows[i]["LocalAuthority"];
dtFirst.Rows[i]["AverageSpeed"] = dtSecond.Rows[i]["AverageSpeed"];
}
return dtFirst;
}
Now , you need to pass datatable as parameter in following method.
MergeData(allTables.ElementAt(0), allTables.ElementAt(1));
You're going to need a unique key on both datatables and merge them together. You could add the SchoolName to your second datatable and merge the two tables on the postcode. Or more preferably, add an id to both of the datatables and merge the two datatables on the id.
Is it possible to add a row to the middle of an existing dataset with c#? I've done a lot of searching and haven't been able to find anything on how to do this. What have I tried? I've tried searching a lot and haven't found anything like an 'insertAt' method for datasets.
Thanks
Mike
The DataSet consists of a collection of DataTable objects so I assume that you are talking about a Datatable, right? If so, it has an InsertAt method:
DataTable dt = dataset.Tables[0]; //Get first datatable from dataset
DataRow row = dt.NewRow();
//fill row
dt.Rows.InsertAt(row,3); //Insert at index 3
DataSet does not have a rows collection, so you can't add a row to it at all.
You can insert a row by index into a DataTable object using DataTable.Rows.InsertAt(row, i). If the table is in a DataSet, your syntax would be DataSet.Tables[i].Rows.InsertAt(row, 0)
In my opinion (though this could take a lot of time), you can create an array or a list array then transfer all the data there from your dataset through for loop or any loop...then put an if statement inside to check where you want to put your extra data like this:
List<string> arrayList = dataset;// i know this is not possible just showing you that you have to put all your data from dataset to array:)
List <string> newList = new List<string>();//its up to you if you want to put another temporary array or you could simply output your data from the loop.
//THE LOOP
for(int i = 0; i<=arrayList.Count(); i++){
if(i == x)//x is the index or you may change this statement its up to you
{
//do the print or pass the data to newList
newList.add(arraList[i]);//not sure about this. its been a while since the last time i use this array list..
}
}
another way is customize your query(if your pulling out some data from database)
happy coding:)
Here's a short sample of doing it:
class Program
{
static void Main(string[] args)
{
DataSet ds = new DataSet();
DataTable dt = ds.Tables.Add("Table");
dt.Columns.Add("Id");
for (int i = 0; i < 10; i++)
{
dt.Rows.Add(new object[]{i});
}
var newRow=dt.NewRow();
newRow.ItemArray=new string[]{(dt.Rows.Count/2).ToString()+".middle"};
dt.Rows.InsertAt(newRow, dt.Rows.Count / 2);
}
}
How can I copy 1 data column from 1 data table to a new datatable. When I try to do it, I get the error Column 'XXX' already belongs to another DataTable.?
dataColumn = datatable1.Columns[1];
datatable2 = new DataTable();
datatable2.Columns.Add(dataColumn);
Thanks in Advance
You cannot copy DataColumns. What you'll need to do is create a new DataColumn in the new datatable with the same data type as in the old datatable's column, and then you need to run a FOR loop to bring in all the data from the old datatable to the new datatable.
See the following code. This assumes that the datatables have exactly the same number of rows.
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt2.Columns.Add("ColumnA", dt1.Columns["ColumnA"].DataType);
for (int i = 0; i < dt1.Rows.Count; i++)
{
dt2.Rows[i]["ColumnA"] = dt1.Rows[i]["ColumnA"];
}
Also, If the data you are copying are reference types and not value types you might want to see if a .Clone() method is available for the type, or make one yourself. Just doing 'this = that' in the FOR loop will not work on reference types.
You cannot copy a DataColumn. (DataColumns are very tightly coupled with their tables)
Instead, you can add a new column with the same name and datatype.
You might be looking for DataTable.Clone(), which will create a structual copy of an entire table. (With the same schema, but no data)
Just a thought, are your DataTables both in the same DataSet?
If so, you can create a named DataRelation between the columns of two tables (think foreign key).
Then you can add a Calculated DataColumn to your table that has its Expression property set to "Child(RelationName).ColumnName" or "Parent(RelationName).ColumnName" depending on the direction of the relationship.
This will give you the same effect as copying the column, but I believe it only evaluates it lazily. So maybe it will give you what you need.
There is an example here of how this works. The example uses the Sum aggregate function, but you just need to reference the column name and it will duplicate it in your DataTable
myDataSet.Relations.Add(
"Orders2OrderLines",
myDataSet.Tables["Orders"].Columns["OrderID"],
myDataSet.Tables["OrderLines"].Columns["OrderID"]);
ordersTable.Columns.Add("OrderTotal", typeof(decimal), "Sum(Child(Orders2OrderLines).ExtendedPrice)");
HTH
The problem is caused by the c# can not reuse the object instance created and uses it on multiples DataTables. For this it is necessary to create a new object DataCollumn for each loop iteration.
foreach (DataTable table in DATASET.Tables)
{
DataColumn yourDataCollumn = new DataColumn("Name of DataCollumn", typeof(Your data type));
// your logic here
}
Hope it's help...
I used the below to merge two tables using mostly LINQ and only looping through the rows at the end. I wouldn't call it pretty but it does work. Using the join to prevent some of the assumptions listed above.
DataTable tableOne = getTableOne();
DataTable tableTwo = getTableTwo();
var oneColumns = tableOne.Columns.Cast<DataColumn>()
.Select(p => new Column(p.ColumnName, DataType))
.ToArray();
var twoColumns = tableTwo.Columns.Cast<DataColumn>()
.Select(p => new DataColumn(p.ColumnName, p.DataType))
.ToArray();
var matches = (from a in tableOne.AsEnumerable()
join b in tableTwo.AsEnumerable() on a["column_name"] equals b["column_name"]
select a.ItemArray.Concat(b.ItemArray)).ToArray();
DataTable merged = new DataTable();
merged.Columns.AddRange(oneColumns);
merged.Columns.AddRange(twoColumns);
foreach (var m in matches) { merged.Rows.Add(m.ToArray()); }
No looping required , Refer this , Hope this should solve your problem...
DataTable dt = new DataTable();
//fill the dt here
DataTable dt2 = new DataTable();
string[] strCols = {"Column Name to copy"};
dt2 = dt.DefaultView.ToTable("newTableName", false, strCols);