I have a dataTable with 4 columns ,
I want to select one column without foreach or any other expensive loop and my result must be a new data table with one column ,How can I do this;
DataTable leaveTypesPerPersonnel = LeaveGroup.GetLeaveTypesPerPersonnels(dtPersonnel.row);
leaveTypesPerPersonnel has this columns :
[ID,Guid,LeaveTypeID,Code]
I want Filter leaveTypesPerPersonnel wihtout foreach and get new datatable with just Column [ID]
NOTE: Output must be a Datatable With one column.
leaveTypesPerPersonnel.Columns.Remove("Guid");
leaveTypesPerPersonnel.Columns.Remove("LeaveTypeID");
leaveTypesPerPersonnel.Columns.Remove("Code");
or
DataTable dt= new DataView(leaveTypesPerPersonnel).ToTable(false,"ID");
You should be able to run a quick LINQ statement against the data table.
var results = (from item in leaveTypesPerPersonnel
select item.ID);
This will give you an IEnumerable if I remember correctly. It's not a DataTable, but might provide a solution to your problem as well.
Here is a try on how to search and convert the result to DataTable
var dataTable = leaveTypesPerPersonnel.Rows.Cast<DataRow>().ToList().Where(x=> x["ID"] == 21).CopyToDataTable().DefaultView.ToTable(false, "ID");
Or
var dataTable = leaveTypesPerPersonnel.Select("ID = 21").CopyToDataTable().DefaultView.ToTable(false, "ID");
Or
var dataTable = leaveTypesPerPersonnel.Rows.Cast<DataRow>().ToList().CopyToDataTable().DefaultView.ToTable(false, "ID");
Related
I have a DataTable where sometimes values in all columns in two or more rows repeat. I would like to get distinct DataTable. The solutions from here and here don't work for me because I have many columns and depending on some conditions, the number of columns changes.
I was thinking maybe something like this
System.Data.DataTable table = new System.Data.DataTable(); // already fulfilled table
DataView view = new DataView(table);
var tableDistinct = view.ToTable(true, table.Columns);
But I can't pass table.Columns as an argument.
I don't know what's going wrong because you haven't said what's not working. However, you could use LINQ(-TO-DataTable):
table = table.AsEnumerable()
.GroupBy(r => new{ Col1 = r["Col1"], Col2 = r["Col2"], Col3 = r["Col3"] })
.Select(g => g.First())
.CopyToDataTable();
Change the columns in the anonymous type according to your column-list.
The ToTable access a list of string params, the following should convert all your columns to array of string so you don't have to enter them manually
System.Data.DataTable table = new System.Data.DataTable(); // already fulfilled table
DataView view = new DataView(table);
var tableDistinct = view.ToTable(true, table.Columns.Cast<DataColumn>().Select(z=>z.ColumnName).ToArray());
This is my code:
SqlCommand vmpCmd = new SqlCommand("sp", connectionstring);
SqlDataAdapter DAvmp = new SqlDataAdapter(vmpCmd);
DataSet DSvmp = new DataSet();
DSvmp.Clear();
DAvmp.Fill(DSvmp);
DataTable table;
table = DSvmp.Tables[0];
from that table I need to take all the rows that its Campaign column exists in this list List<string> compaines = new List<string>();
What have I tried
I tried this:
table = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row);
but I got this exception on the select:
Cannot implicitly convert type 'System.Data.EnumerableRowCollection<System.Data.DataRow>' to 'System.Data.DataTable'
If you want to convert an IEnumerable<DataRow> to a DataTable you can use CopyToDataTable:
var filteredRows = table.AsEnumerable()
.Where(row => compaines.Contains(row.Field<string>("Campaign")));
table = filteredRows.CopyToDataTable();
But instead of filtering when you've already retrieved all records i would do that in the database. Here's a nice trick to build parameters from a List<string>.
Use CopyToDataTable extension method to convert IEnumerable<DataRow> to DataTable
table = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row).CopyToDataTable();
Get the values in var data type like this as LINQ returns System.Data.EnumerableRowCollection<System.Data.DataRow which cannot be implicity converted to Datatable type
var filteredTable = (from row in table.AsEnumerable()
where compaines.Contains(row.Field<string>("Campaign"))
select row);
If you want the retrieved records for other operations then its fine otherwise it's better to use filter in your query and for that there are below methods:
You can use parameterized query
You can build your query string using String.Join() from your List
I am using datatable to return me distinct records but somehow its not returning me distinct records
I tried like
dt.DefaultView.ToTable(true, "Id");
foreach (DataRow row in dt.Rows)
{
System.Diagnostics.Debug.Write(row["Id"]);
}
It still returns me all the records. What could be wrong here?
UPDATE
My sql is as below
select t.Update ,t.id as Id, t.name ,t.toDate,t.Age from tableA t Where t.Id = 55
union
select t.Update ,t.id as Id, t.name ,t.toDate,t.Age from tableB t Where t.Id = 55
order by Id
Its very hard to do distinct in my query as there are many columns than mentioned here.
If you use a database it would be better to use sql to return only distinct records(e.g. by using DISTINCT, GROUP BY or a window function).
If you want to filter the table in memory you could also use Linq-To-DataSet:
dt = dt.AsEnumerable()
.GroupBy(r=>r.Field<int>("Id")) // assuming that the type is `int`
.Select(g=>g.First()) // take the first row of each group arbitrarily
.CopyToDataTable();
Note that the power of Linq starts when you want to filter these rows or if you don't want to take the first row of each id-group arbitrarily but for example the last row(acc. to a DateTime field). Maybe you also want to order the groups or just return the first ten. No problem, just use OrderBy and Take.
The issue is that you're not grabbing the new table:
var newDt = dt.DefaultView.ToTable(true, "Id");
foreach (DataRow dr in newDt.Rows) ...
the ToTable method doesn't modify the existing table - it creates a new one.
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "Id");
you are not assigning the return value to any variable, try this
DataTable dtnew = dt.DefaultView.ToTable(true, "Id");
foreach (DataRow row in dtnew.Rows)
{
System.Diagnostics.Debug.Write(row["Id"]);
}
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);
I'm running a LINQ query on a datatable in c#.
I want to select specific columns rather than the whole row and enter the result into a datatable. How can i do that??
My Code:
public DataTable getConversions(string c_to, string p_to)
{
var query = from r in matrix.AsEnumerable()
where r.Field<string>("c_to") == c_to &&
r.Field<string>("p_to") == p_to
select r;
DataTable conversions = query.CopyToDataTable();
If you already know beforehand how many columns your new DataTable would have, you can do something like this:
DataTable matrix = ... // get matrix values from db
DataTable newDataTable = new DataTable();
newDataTable.Columns.Add("c_to", typeof(string));
newDataTable.Columns.Add("p_to", typeof(string));
var query = from r in matrix.AsEnumerable()
where r.Field<string>("c_to") == "foo" &&
r.Field<string>("p_to") == "bar"
let objectArray = new object[]
{
r.Field<string>("c_to"), r.Field<string>("p_to")
}
select objectArray;
foreach (var array in query)
{
newDataTable.Rows.Add(array);
}
Try Access DataTable easiest way which can help you for getting perfect idea for accessing DataTable, DataSet using Linq...
Consider following example, suppose we have DataTable like below.
DataTable ObjDt = new DataTable("List");
ObjDt.Columns.Add("WorkName", typeof(string));
ObjDt.Columns.Add("Price", typeof(decimal));
ObjDt.Columns.Add("Area", typeof(string));
ObjDt.Columns.Add("Quantity",typeof(int));
ObjDt.Columns.Add("Breath",typeof(decimal));
ObjDt.Columns.Add("Length",typeof(decimal));
Here above is the code for DatTable, here we assume that there are some data are available in this DataTable, and we have to bind Grid view of particular by processing some data as shown below.
Area | Quantity | Breath | Length | Price = Quantity * breath *Length
Than we have to fire following query which will give us exact result as we want.
var data = ObjDt.AsEnumerable().Select
(r => new
{
Area = r.Field<string>("Area"),
Que = r.Field<int>("Quantity"),
Breath = r.Field<decimal>("Breath"),
Length = r.Field<decimal>("Length"),
totLen = r.Field<int>("Quantity") * (r.Field<decimal>("Breath") * r.Field<decimal>("Length"))
}).ToList();
We just have to assign this data variable as Data Source.
By using this simple Linq query we can get all our accepts, and also we can perform all other LINQ queries with this…
Here I get only three specific columns from mainDataTable and use the filter
DataTable checkedParams = mainDataTable.Select("checked = true").CopyToDataTable()
.DefaultView.ToTable(false, "lagerID", "reservePeriod", "discount");
LINQ is very effective and easy to use on Lists rather than DataTable. I can see the above answers have a loop(for, foreach), which I will not prefer.
So the best thing to select a perticular column from a DataTable is just use a DataView to filter the column and use it as you want.
Find it here how to do this.
DataView dtView = new DataView(dtYourDataTable);
DataTable dtTableWithOneColumn= dtView .ToTable(true, "ColumnA");
Now the DataTable dtTableWithOneColumn contains only one column(ColumnA).
Your select statement is returning a sequence of anonymous type , not a sequence of DataRows. CopyToDataTable() is only available on IEnumerable<T> where T is or derives from DataRow. You can select r the row object to call CopyToDataTable on it.
var query = from r in matrix.AsEnumerable()
where r.Field<string>("c_to") == c_to &&
r.Field<string>("p_to") == p_to
select r;
DataTable conversions = query.CopyToDataTable();
You can also implement CopyToDataTable Where the Generic Type T Is Not a DataRow.