How to get the Selected columns form the DataTable? For e.g my BaseTable has three columns, ColumnA, ColumnB and ColumnC. Now as part of intermediate operations, I need to retrieve all the rows only from the ColumnA. Is there any predefined formula just like DataTable.Select?
DataView.ToTable Method.
DataView view = new DataView(MyDataTable);
DataTable distinctValues = view.ToTable(true, "ColumnA");
Now you can select.
DataRow[] myRows = distinctValues.Select();
From this question: How to select distinct rows in a datatable and store into an array you can get the distinct values:
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "ColumnA");
If you're dealing with a large DataTable and care about the performance, I would suggest something like the following in .NET 2.0. I'm assuming the type of the data you're displaying is a string so please change as necessary.
Dictionary<string,string> colA = new Dictionary<string,string>();
foreach (DataRow row in table.Rows) {
colA[(string)row["ColumnA"]] = "";
}
return colA.Keys;
Related
I have a DataTable(dataTable1) that have 25-30 columns. I want to bind a DataGridView by creating a small DataTable (dataTable2) that will have few columns (may 5-10) from the existing DataTable.
So my main task is to create a DataTable with fewer columns from the existing one.
Here is the code what I have tried so for..
DataTable subDataTable()
{
DataTable smallTable=new DataTable();
smallTable =dataTable1;// dataTable1 is already filled with data
smallTable.Columns.Remove("Column2");
smallTable.Columns.Remove("Column5");
smallTable.Columns.Remove("Column6");
smallTable.Columns.Remove("Column13");
smallTable.Columns.Remove("Column16");
return smallTable;
}
Its working fine. But I'm looking if there any better way.
You can try to convert your DataTable to IEnumerable,and Select necessary fields with linq like this:
var myValues = dataTable1.AsEnumerable()
.Select(x => new { col1 = x["Column1"], col2 = x["Column2"]..});
dataGridView.DataSource = myValues;
Your code will not work because you all you do is assign a variable smallTable with reference to dataTable1 and you removing columns from your original table object
Linq is faster to write but here is what you want to do to understand your issue:
DataTable smallTable = dataTable1.Clone(); // Copy data structure
// Now you can remove your columns
smallTable.Columns.Remove("Column2");
......
foreach (var row in dataTable1.Rows) // iterate all rows
{
var newRow = smallTable.NewRow();
foreach (var col in smallTable.Columns) // and iterate only needed columns
{
newRow[col.ColumnName] = row[col.ColumnName];
}
}
This is pretty much what sugar-coated by Linq
DataView dv = new DataView(dataTable1);
DataTable smallTable = dv.ToTable(true, new string[] { "Column2", "Column5"...});
https://social.msdn.microsoft.com/Forums/en-US/ac2c7c95-66d6-4db6-a6fb-4dccd5fa701e/is-there-a-better-way-to-get-subtable-with-selected-columns-of-a-datatable?forum=adodotnetdataset
Tomer.
I've found this piece of code that can be used to get all distinct values. But my datatable has 10 columns. The distinctValues only shows the columns I write in the toTable(); Is it possible to use this function, but also show the rest of the columns?
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "Column1", "Column2");
Unless those columns you mention are the full key to the table, there is no guarantee that for a particular combination of those two columns the other columns will have exactly one value.
And if they were the key, then there would be no need to use a "distinct" filter.
You can use Linq-To-DataTable
var distinct = from row in table.AsEnumerable()
group row by new
{
Col1 = row.Field<string>("Column1"),
Col2 = row.Field<string>("Column2")
} into Group
select Group.First()
DataTable tblDistinct = distinctRows.CopyToDataTable();
(assuming that you just want an arbitrary row[the first])
In my project there are two datatables dtFail and dtFailed (dtFailed has nothing but column names declarations). dtFail has duplicate "EmployeeName" column values. so i took a dataview dvFail and did the process to make them distinct as shown in the below code:
dtFail
I tried the below code:
DataView dvFail = new DataView(dtFail);
dtFail = dvFail.ToTable(true, "EmployeeName"); //showing only one column in dtFail
dtFailed (only one column)
If i do like below
DataView dvFail = new DataView(dtFail);
dtFail = dvFail.ToTable(true, "EmployeeName","EmployeeRole","Status");
dtFailed (showing but with duplicate rows)
Then the datatable dtFailed is storing duplicate "EmployeeName" also.
Please Help
Thanks in Advance.
Try this query-
DataTable distinctTable = originalTable.DefaultView.ToTable( /*distinct*/ true);
For more info hit below link-
https://social.msdn.microsoft.com/Forums/en-US/ed9c6a6a-a93e-4bf5-a892-d8471b84aa3b/distinct-in-datatable-or-dataview?forum=adodotnetdataset
I hope this would have helped you.
SOLUTION 1:
Based on the question my understanding is, we need to consider duplicates based on EmployeeName and we need not worry about other columns. If that is the case below solution works better.
foreach(DataRow r in dtFail.AsEnumerable())
{
if (!dt1.AsEnumerable().Any(r1 => r1["EmployeeName"] == r["EmployeeName"]))
{
// if you don't want to copy entire row create new DataRow
// with required fields and add that row.
dt1.Rows.Add(r.ItemArray);
}
}
if you want you can put dt1 back to dtFail.
SOLUTION 2:
If we need to consider distinct rows I prefer below solution.
var temp = dtFail.AsEnumerable().Distinct();
dtFail = temp.CopyToDataTable();
I'm not sure it will be helpful or not. As far as I get from your question that you want EmployeeName to be distinct irrelevant to other columns. But if you do ToTable and turn on the distinct flag it will give all the distinct rows, doesn't matter how many columns are involved there. So if you mention only EmployeeName it will obviously give you distinct EmployeeNames, not all the columns associated with it.
So, thats what I did, initially select only the distinct EmployeeName columns and put it into a temp DataTable dtt.
DataTable dtt = dvFail.DefaultView.ToTable(true, "EmployeeName");
Secondly I've created another temp DataTable where we put the segregated rows from the main DataTable dtFail and set the column names manually.
DataTable TempDataTable = new DataTable();
DataTable dtFailed = new DataTable();
Prepare the columns in the dtFailed DataTable.
if (dtFailed.Columns.Count == 0)
{
dtFailed.Columns.Add("EmployeeName");
dtFailed.Columns.Add("EmployeeRole");
dtFailed.Columns.Add("Status");
dtFailed.Columns.Add("Date");
}
Loop through the distinct EmployeeName dtt DataTable and match the EmployeeName and keep that selected first row in the TempDataTable. Finally all rows transferred into the dtFailed.
for (int j = 0; j < dtt.Rows.Count; j++)
{
string EmployeeName = dtt.Rows[j]["EmployeeName"].ToString();
TempDataTable = dvFail.Select("EmployeeName = " + EmployeeName).CopyToDataTable();
dtFailed.Rows.Add(TempDataTable.Rows[0].ItemArray);
}
Let's say I have a table with a Color column. Color can have various values. I have a C# method that can handle items of a given column at a time. Thus, I would like to :
foreach(colorname in mytable.getDistinctColornames)
monocolorMethod(mytable.getSubTableOnlyContainingRowsWithColor(colorname))
How would I do that elegantly ... ?
At all prices, I would avoid copying the data back & forth. I would like kind of a view on the datatable. A view that would only "show" the rows of a given columns, and a "writable" view (i.e. when I write to the filtered subset, the original table is written to)
EDIT :
Let's say I have a 'Car' Table, and I would like to replace 'Sedan' by 'Truck' in column 'Type' for all cars with 'Color=Red'.
How would I do given the following code ?
DataTable cars (...); // the data
DataView dv = cars.DefaultView;
dv.RowFilter = "Color='Red'";
< Here I would like to loop on the DataView>. The following code does not work :
foreach (row in dv.AsEnumerable)
{
if(row["Type"] == "Sedan")
row["Type"] = "Truck";
}
EDIT 2 :
Found this http://msdn.microsoft.com/fr-fr/library/system.data.dataview.allowedit.aspx which suggests
view.AllowEdit = true;
view[0].BeginEdit();
view[0]["FirstName"] = "Mary";
view[0]["LastName"] = "Jones";
view[0].EndEdit();
Check out this:
Querying DataSets – Introduction to LINQ to DataSet
Did you try using DataView class? It looks like exactly what you want to achieve without using LINQ: http://msdn.microsoft.com/en-us/library/fdcwwhez
An example of usage:
Let say there is a DataTable object named _dt with 4 rows in it:
_dt = new DataTable("") {Columns = {new DataColumn("ID"), new DataColumn("Name"), new DataColumn("Order")}};
_dt.Rows.Add(1, "one", 1);
_dt.Rows.Add(2, "two", 3);
_dt.Rows.Add(3, "three", 2);
_dt.Rows.Add(4, "four", 5);
You can easily create DataView which doesn't filter data but perform sorting operation on it:
_dv = new DataView(_dt, "", "Order, Name", DataViewRowState.CurrentRows);
You can also add new rows into the DataView and because it is set on corresponding DataTable that new row will be added directly to _dt object. The sorting order will be updated as well, and new row won't be the last one within the DataView (because sort is done on Order and Name columns)
var newRow = _dv.AddNew();
newRow["ID"] = 5;
newRow["Name"] = "five";
newRow["Order"] = 4;
newRow.EndEdit();
After that code there will be 5 rows in _dt. Editing rows is also quite simple:
var editedRow = _dv[0];
editedRow.BeginEdit();
editedRow["Name"] = "Test";
editedRow.EndEdit();
You can also use DataView.Find() or DataView.FindRows() methods to find a row within the DataView.
I have two datatables D1 and D2.
I merged the datatable D2 with D1 as follows:
D1.Merge(D2);
But now, I want to remove the DataTable D2 from the D1. How to achieve this?
This may not be the most beautiful solution, but you can consider adding a distinctive column to your tables. I set those values by hand, but for example if your datatables are filled from a SQL query, you can easily add that distinctive column in those queries and use them accordingly.
D1.Columns.Add("ORIGINAL_DATATABLE_NAME", typeof(int));
D2.Columns.Add("ORIGINAL_DATATABLE_NAME", typeof(int));
foreach(DataRow row in D1.Rows)
row["ORIGINAL_DATATABLE_NAME"] = 1;
foreach(DataRow row in D2.Rows)
row["ORIGINAL_DATATABLE_NAME"] = 2;
D1.Merge(D2);
DataRow[] rows = D1.Select("ORIGINAL_DATATABLE_NAME=1", "");
DataSet ds = new DataSet();
ds.Merge(rows, false, MissingSchemaAction.Add);
ds.Tables[0].Columns.Remove("ORIGINAL_DATATABLE_NAME");