Create ADO.NET DataView showing only selected Columns - c#

In C# & .NET, can one create a DataView that includes only a proper subset of the DataColumns of a given DataTable?
In terms of relational algebra, one assigns a RowFilter in order to perform a "selection" operation (σ). How would one perform a "projection" operation (π)?

You can't do that, but you can create a copy of the table with only the columns you want :
DataView view = new DataView(table);
DataTable table2 = view.ToTable(false, "FirstColumn", "SecondColumn", "ThirdColumn");
Optionally you can return rows that have distinct values for the selected columns :
DataView view = new DataView(table);
DataTable table2 = view.ToTable(true, "FirstColumn", "SecondColumn", "ThirdColumn");

Well I can't see any reason for "wanting" to do that... Remember, a DataView is just a list of pointers to the rows in the original table, and there is obviously no way to remove columns from the the original table... at least not without affecting every other function utilizing that table... Just only use the columns you want...

create dataview as a swap from one table to other table, and use the dtswap as datasource.
DataView dw = new DataView(dtfee);
DataTable dtswap = new DataTable();
dtswap = dw.ToTable(true,"Fees", "FeeAmount", "Year", "CollectorName", "Month");

DataSet and its associated types have no ability to perform relational operations.

Related

DataTable Select & DataView Sort

Quick Question.
When I use a DataTable.Select("..") without a Sort condition after using a DataView to Sort the DataTable, should the records be returned in Sorted order ?
Using this method I find that in some cases the records aren't being returned in the correct order, it's hit and miss as well - sometimes they are sometimes they aren't.
If I specify a sort condition to the Select then it all works fine, but the performance implications are drastic for large DataTables.
I've tried using the DataView RowFilter to reduce the hitset but every time I change the RowFilter the performance goes south
MyDtable.Load(MyReader); // its am Oracle DataReader
MyView = new DataView(MYDtable);
MyView.Sort = "CODE, TABLE DESC";
DataRow[] MyRecs = MyDtable.Select("TABLE > 'FREDDO' AND CODE > '661991'");
The number of records returned is always correct, it's just the order that may vary (sometimes)
Thanks,
John
John,
Applying a sort order to a DataView does not change the underlying DataTable it represents. So your code snippet using both DataView properties and DataTable.Select() method will not work as you intended.
When sorting and filtering, you must choose which method is best for presenting and maintaining the data. Here are sorting and filtering usages examples for both DataTable and DataView.
Using DataTable
Syntax:
public System.Data.DataRow[] Select (string filterExpression, string sort);
Example:
DataRow[] MyRecs = MyDTable.Select("TABLE > 'FREDDO' AND CODE > '661991'", "CODE, TABLE DESC");
foreach (DataRow rec in MyRecs)
{ . . . . }
Reference: DataTable.Select() Method Reference
Using DataView
Example:
DataView MyView = new DataView(MyDTable);
MyView.Sort = "CODE, TABLE DESC";
MyView.RowFilter = "TABLE > 'FREDDO' AND CODE > '661991'";
Reference: DataView.RowFilter Property Reference
Note the link takes you to Microsoft’s RowFilter property reference page, the included example shows usage information for both RowFilter and Sort properties.
Or
Syntax:
public DataView (System.Data.DataTable table, string RowFilter, string Sort,
System.Data.DataViewRowState RowState);
Example:
DataView MyView = new DataView(
MyDTable,
"TABLE > 'FREDDO' AND CODE > '661991'",
"CODE, TABLE DESC",
DataViewRowState.CurrentRows);
foreach ( DataRowView rec in MyView )
{ . . . . }
Reference: DataView Class Constructor Reference
Both methods will return the data filtered and sorted correctly. The difference is in how the data is being returned. You must choose the method whose return object best suit your needs.

Clear Sorting from DataView

I have a dataview. Source of dataview is a view from sql server.
Dataview is sorted. Like this:
dv_building.Sort = "bld_number"
this dataview is a datasource to my datagird1:
DataGrid1.DataSource = dv_building
Now I want to remove sorting dv_building.Sort = String.Empty but the view of my data grid was changed, because sorting was removed, ie dataview was returned to their default sorting, probably by clustered index.
How can I remove sorting, but the actual sorting remain by bld_number? Is it possible?
I found this workaround to achieve requested behaviour: implementation of class derived from Datatable is accessible for me, additional column appended to Columns:
Columns.AddRange(
new DataColumn[N]
{
...
new DataColumn("Order", typeof (int))
}
I enumerate this column with order numbers after each data view column modification (column participated in sort). When I need freeze sorting I switch DataView.Sort property to this "Order" column. To unfreeze - dataView.Sort = regularSortCriterion.

Adding a column from one Datatable to another datatable of a dataset [duplicate]

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);

How to get unique records of specific columns of data table

I have a DataTable imported from Excel file.
Data i need is only unique from specific columns of the DataTable.
The unique data i meant is like when a command DISTINCT is used in SQL Select Query.
I want to get the list of the unique data from the DataTable Column and put them into List
I think LinQ can be used for this matter but i'm not so familiar with it.
I was thinking of code like this below
var data is from MyDataTable
where MyDataTable.ColumnName = "SpecificColumn"
select MyDataTable["SpecificColumn"]).UniqueData;
List<string> MyUniqueData = new List<string>();
foreach(object obj in data)
{
if(MyUniqueData.NotContain(obj))
MyUniqueData.add(obj);
}
I hope someone can drop off some knowledge to me.
var unique = data.Distinct().ToList();
What you're looking for is .Distinct(). See MSDN documentation here. You can specify your own comparer if you need something specific and it will return only unique records.
If you have a Datatable or DataView, inorder to get unique records from a column, you have to write this.
this would be simple.
DataTable dtNew = dt.DefaultView.ToTable(true, "ColName"); // for Datatable
DataTable dtnew= dv.ToTable(true, "ColName"); // for DataView

DataView.Count different DataView.Table.Rows.Count

I am using C# and .NET 3.5 and have a GridView that I am setting the dataSource programatically in the code-behind page. I have data in a DataTable and then depending on a column value (isValid boolean) of each Row, I create a new row using DataRowView.AddNew() method into 1 of 2 DataViews - dvValid or dvInvalid. I am NOT creating a new DataTable.NewRow to add to the DataView Table. Then I bind the GridView to the appropriate dataView.
There is a problem when I am sorting the GridView. I am having a problem with 1 row not being sorted correctly, all other rows are sorted fine. I debugged my code and found that the DataView.Count is 1 more than the DataView.Table.Rows.Count even though I am calling DataView.Table.AcceptChanges() method. This is strange since the dataTable should have all committed rows and therefore the counts should be the same.
So why are the 2 counts different? A DataView is a subset of the DataTable so should it not have equal or less rows than the DataTable.
When I populate the DataView, should I first create the DataTables rather than creating the DataView directly? Right now, I am directly creating a DataRowView without a dDataTableRow, is this the correct approach?
Thanks for your help.
Code snippet : C#
...
//get the data as DataTable
members = GetMemberDataTable ();
//create views from a new DataTable with no rows
dvValidMembers = new DataView (CreateMembersDT("ValidMembers"));
dvInValidMembers = new DataView (CreateMembersDT("InvalidMembers"));
//iterate thru each row and put into appropriate DataView
foreach (DataRow memberRow in members.Rows)
{
if ((bool)memberRow["isValid"])
//Add to valid members Dview
member = dvValidMembers.AddNew();
else
//add to InValid members Dview
member = dvInvalidMembers.AddNew();
member["memberID"] = memberRow["memID"];
} //foreach
dvInvalidMembers.Table.AcceptChanges();
dvValidMembers.Table.AcceptChanges();
}
private System.Data.DataTable CreateMembersDT ( string tableName)
{
System.Data.DataTable dtMembers = new System.Data.DataTable(tableName);
dtMembers.Columns.Add(new DataColumn("memID", typeof(int)));
return dtMembers;
}
That 1 row that isn't sorting right, could that be the last row?
I think you are missing a DataView.EndEdit():
foreach (DataRow memberRow in members.Rows)
{
DataView dv;
if (...)
//Add to valid members Dview
dv = dvValidMembers;
else
dv = dvInvalidMembers;
member = dv.Addnew();
member["memberID"] = memberRow["memID"];
dv.EndEdit();
}
But I would also like to note that you could probably use 2 Views with a Filter on isValid and then you would only need to point them to the original members table.

Categories