Remove a column from DataTable based on a where condition using linq - c#

I have a Dataset which contains many dataTable .
The datatables looks like as follows,
column1 column2 column3 Name
NA NA NA Ivan
Now I want to remove columns from all datatables in the dataset where row value is 'NA'.
How can I do this using Linq if possible?

You can remove column from collecion via method Remove, and linq can only help you find desired columns.
Find desired columns and then remove them.
var dt = new DataTable();
List<DataColumn> delete = new List<DataColumn>();
foreach (DataRow row in dt.Rows)
foreach (DataColumn col in dt.Columns)
if (row[col]?.ToString() == "NA" && !delete.Contains(col))
delete.Add(col);
foreach (var col in delete)
dt.Columns.Remove(col);

I guess that you actually want to remove all string-columns of all tables where all values of all rows are NA(or na). Then this works as expected:
foreach (DataTable table in ds.Tables)
{
List<DataColumn> stringColumns = table.Columns.Cast<DataColumn>()
.Where(c => c.DataType == typeof(string))
.ToList();
var columnsAllNotAvailable = stringColumns
.Where(c => table.AsEnumerable()
.All(r => String.Equals(r.Field<string>(c), "NA", StringComparison.InvariantCultureIgnoreCase)));
foreach(DataColumn col in columnsAllNotAvailable)
table.Columns.Remove(col);
}

Related

Not able to delete multiple rows from datatable

I have following code. Data is datable
DataRow[] rows;
rows = data.Select("meta_key = '_edit_lock'");
rows = data.Select("meta_key = 'resume_path'");
foreach (DataRow r in rows)
r.Delete();
data.AcceptChanges();
I can only delete resume_path row from datatable and can't delete _edit_lock.
The select filter should include both conditions, like in the code below.
DataRow[] rows;
rows = data.Select("meta_key = '_edit_lock' OR meta_key = 'resume_path'");
foreach (DataRow r in rows) {
r.Delete();
}
data.AcceptChanges();
Select filter could also be expressed as
"meta_key IN ('_edit_lock', 'resume_path')"

Compare two data tables and insert into another table based on column name in C#

I have two data tables Table1 and Table2. I want to compare a value SourceField and insert the row of both table into a new data table.
Table #1 - Mapping table
Key SourceField
------------------
null name
A101 V1
A102 V2
A103 V3
Table #2 - Source table
Name V1 V2 V3
-----------------------
10001 1 2 3
Table #3 - Output table
Name Value Key
--------------------
10001 1 A101
10001 2 A102
10001 3 A103
Regards,
Manish
For DataTable , following solution will work for you.
I tested it. I used the same structure that you mentioned in the question.
DataTable table1 = new DataTable();
table1.Columns.Add("Key");
table1.Columns.Add("SourceField");
table1.Rows.Add("A101", "V1");
table1.Rows.Add("A102", "V2");
table1.Rows.Add("A103", "V3");
DataTable table2 = new DataTable();
table2.Columns.Add("Name");
table2.Columns.Add("V1");
table2.Columns.Add("V2");
table2.Columns.Add("V3");
table2.Rows.Add("10001", 1, 2, 3);
DataTable table3 = new DataTable();
table3.Columns.Add("Name");
table3.Columns.Add("Value");
table3.Columns.Add("Key");
// LOOP FOR COMPARING THE DIFFERENT COLUMNS AND VALUES FROM DIFFERENT DATATABLES
foreach (DataRow drtable1 in table1.Rows)
{
foreach (DataRow drtable2 in table2.Rows)
{
if ( drtable2[Convert.ToString(drtable1["SourceField"])] != null)
{
table3.Rows.Add(drtable2["Name"], drtable2[Convert.ToString(drtable1["SourceField"])], drtable1["Key"]);
}
}
}
Result (snap from Visual Studio)
UPDATE
Need to add one more condition in loop for checking blank value for Key column.
// LOOP FOR COMPARING THE DIFFERENT COLUMNS AND VALUES FROM DIFFERENT DATATABLES
foreach (DataRow drtable1 in table1.Rows)
{
foreach (DataRow drtable2 in table2.Rows)
{
if (drtable2[Convert.ToString(drtable1["SourceField"])] != null && Convert.ToString(drtable1["Key"]).Trim() != string.Empty)
{
table3.Rows.Add(drtable2["Name"], drtable2[Convert.ToString(drtable1["SourceField"])], drtable1["Key"]);
}
}
}
You can create a new DataSet:
DataSet dset = new DataSet();
DataTable datatable3 = new DataTable("OutputTable");
datatable3.Columns.Add(new DataColumn("Name",typeof(string)));
datatable3.Columns.Add(new DataColumn("Value", typeof(int)));
datatable3.Columns.Add(new DataColumn("Key", typeof(string)));
//do a foreach or any other operation here
//you can add a new row to the datatable like that:
drow["Name"] = "10001";
drow["Value"] = 3;
drow["Key"] = "A103";
DataRow drow = datatable3.NewRow();
datatable3.Rows.Add(drow);
//after adding ALL rows, you have to add the datatable to the dataset
dset.Tables.Add(datatable3);
Loop through an existing dataset (I suppose you already have ds1 and ds2 as seperate datatables):
foreach (DataRow row1 in datatable1.Rows)
{
foreach (DataRow row2 in datatable2.Rows)
{
//example comparasion
if (row1["SourceField"] == row2["SourceField")
{
datatable3.Rows.Add(....) //see above examples how to add a row
}
}
}

Splitting a DataTable into 2 using a column index

I have a stored procedure which selects the differences between rows in a table and returns a DataTable in the following format:
col1_A, col2_A, col3_A, col1_B, col2_B, col3B
I would like to split the DataTable into 2 separate DataTables so it looks like
TableA
col1
col2
col3
TableB
col1
col2
col3
This code gets me the column index.
foreach (DataColumn col in DT.Columns)
{
if (!col.ColumnName.EndsWith("B"))
tableBIndex += 1;
else
break;
}
but from here I'm not sure how to separate the rows into 2 DataTables. Any ideas on the best way to accomplish this?
This should do the trick and fill both tables in one loop:
DataColumn[] aCols = table.Columns.Cast<DataColumn>()
.Where(c => c.ColumnName.EndsWith("A"))
.Select(c => new DataColumn(c.ColumnName, c.DataType))
.ToArray();
DataColumn[] bCols = table.Columns.Cast<DataColumn>()
.Where(c => c.ColumnName.EndsWith("B"))
.Select(c => new DataColumn(c.ColumnName, c.DataType))
.ToArray();
var TableA = new DataTable();
TableA.Columns.AddRange(aCols);
var TableB = new DataTable();
TableB.Columns.AddRange(bCols);
foreach (DataRow row in table.Rows)
{
DataRow aRow = TableA.Rows.Add();
DataRow bRow = TableB.Rows.Add();
foreach (DataColumn aCol in aCols)
aRow.SetField(aCol, row[aCol.ColumnName]);
foreach (DataColumn bCol in bCols)
bRow.SetField(bCol, row[bCol.ColumnName]);
}
I'd recommend creating two new tables and copying out values like this.
DataTable one = new DataTable();
DataTable two = new DataTable();
foreach (DataColumn col in DT.Columns)
{
if (!col.ColumnName.EndsWith("B"))
{
one.Columns.Add(col.ColumnName.Replace("_A", ""));
foreach (DataRow row in DT.Rows)
{
one.Rows.Add(row[col.ColumnName]);
}
}
else
{
one.Columns.Add(col.ColumnName.Replace("_B", ""));
foreach (DataRow row in DT.Rows)
{
two.Rows.Add(row[col.ColumnName]);
}
}
}

Looping through 2 datatable and adding values to third

I have created 3 datatables
var dt1= new DataTable();
var dt2= new DataTable();
var dt3= new DataTable();
Then i loop
foreach (DataRow row1 in dt1.Rows)
{
dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1= row2["Id"];
if (Id1 == Id2)
{
dt3.rows["Name"] = "" ; // doesnt work
}
}
}
As you can see that i loop on 2 datatables. Then in inner loop i check if the records matches. Now if the record matches then i want to update column "Name" on dt3 datatable.
I tried using
dt3.rows["Name"] = "" ;
But this doesnt work. I know the reason that its because i again need to loop on dt3 datatable and
assign values to column in that loop. But not sure how to do it and if there is even more better solution. I mean we can find id in dt3 datatable and then update value. But not sure how to do it
Is there more intelligent solution than looping on 2 table?
The first foreach is not needed. A simple DataTable.Copy will bring all the data and structure from the original table in the destination table. Then looping on the second table and Select on the third to find the matching rows and clear the name.
dt3 = dt1.Copy();
foreach (DataRow row2 in dt2.Rows)
{
DataRow[] match = dt3.Select("ID=" + row2["ID"].ToString());
if(match.Lenght > 0)
match[0]["Name"] = "" ;
}
Not sure if this is more performant from the other answers. Need to be tested
dt3.rows doesn't work, you want to change the name of the row that you have added now. This should work:
foreach (DataRow row1 in dt1.Rows)
{
DataRow newRow = dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1 = row2["Id"];
if (Id1 == Id2)
{
newRow["Name"] = "new Name";
}
}
}
Try this:
foreach (DataRow row1 in dt1.Rows)
{
var row = dt3.Rows.Add(row1.ItemArray);
foreach (DataRow row2 in dt2.Rows)
{
var Id2 = row1["Id"];
var Id1= row2["Id"];
if (Id1 == Id2)
{
row["Name"] = ""; //maybe works
}
}
}
How about,
dt2Lookup = new HashSet(
dt2.AsEnumerable().Select(row => row.Field<int>("Id")));
dt3 = dt1.Clone();
forreach (var row In dt1.AsEnumerable())
{
var newRow = dt3.Rows.Add(row.ItemArray)
if (dt2lookup.Contains(row.Field<int>("Id"))
{
newRow.SetField("Name", string.Empty);
}
}
The HashSet should provide good lookup performance.
dt3 = dt1.Copy();
var RowDictionary = dt3.Rows.OfType<DataRow>().ToDictionary(dr => dr["ID"].ToString());
//replace by Dictionary<string,List<DataRow>> in case ID is not unique and fill it with a foreach loop.
foreach (DataRow row2 in dt2.Rows)
{
DataRow Match;
if (c.TryGetValue(row2["ID"].ToString(), out Match))
{
Match["Name"] = "";
}
}
You should call:
dt3.rows[dt3.rows.Count - 1].Columns["Name"] = "" ;

Looping through a DataTable

Well. I have a DataTable with multiple columns and multiple rows.
I want to loop through the DataTable dynamically basically the output should look as follows excluding the braces :
Name (DataColumn)
Tom (DataRow)
Peter (DataRow)
Surname (DataColumn)
Smith (DataRow)
Brown (DataRow)
foreach (DataColumn col in rightsTable.Columns)
{
foreach (DataRow row in rightsTable.Rows)
{
//output
}
}
I typed that out and noticed this would not work. Can someone please advice on a better way of doing this?
foreach (DataColumn col in rightsTable.Columns)
{
foreach (DataRow row in rightsTable.Rows)
{
Console.WriteLine(row[col.ColumnName].ToString());
}
}
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
Console.WriteLine(row[col]);
}
Please try the following code below:
//Here I am using a reader object to fetch data from database, along with sqlcommand onject (cmd).
//Once the data is loaded to the Datatable object (datatable) you can loop through it using the datatable.rows.count prop.
using (reader = cmd.ExecuteReader())
{
// Load the Data table object
dataTable.Load(reader);
if (dataTable.Rows.Count > 0)
{
DataColumn col = dataTable.Columns["YourColumnName"];
foreach (DataRow row in dataTable.Rows)
{
strJsonData = row[col].ToString();
}
}
}
If you want to change the contents of each and every cell in a datatable then we need to Create another Datatable and bind it as follows using "Import Row". If we don't create another table it will throw an Exception saying "Collection was Modified".
Consider the following code.
//New Datatable created which will have updated cells
DataTable dtUpdated = new DataTable();
//This gives similar schema to the new datatable
dtUpdated = dtReports.Clone();
foreach (DataRow row in dtReports.Rows)
{
for (int i = 0; i < dtReports.Columns.Count; i++)
{
string oldVal = row[i].ToString();
string newVal = "{"+oldVal;
row[i] = newVal;
}
dtUpdated.ImportRow(row);
}
This will have all the cells preceding with Paranthesis({)

Categories

Resources