I need to dynamically generate a query to access certain columns from a datatable.
string cols="row[Id],row[UserId], row[Code]";
var result= (from DataRow row in dt.Rows
select cols);
but this only returns "row[Id],row[UserId], row[Code]". How can I access the values in those columns?
I doubt this problem can be solved elegantly with a linq-based solution. It can be solved pretty easily using a loop and by accessing the column of the DataRow using the Item property.
public IEnumerable<object[]> GetValues(IList<string> columns, DataTable dt) {
foreach (var row in dt.Rows) {
var rowResult = new object[columns.Count];
for (var col = 0; col < columns.Count; col++) {
rowResult[col] = row.Item[columns[col]];
}
yield return rowResult;
}
}
Why not putting it in a dictionary? Dictionary<string, object> the key is the column name and the value is the value of the column.
string[] cols = new string[] { "Id", "UserId", "Code" };
var result = (from DataRow row in dt.Rows
select cols.ToDictionary(c => c, c => row[c]));
Related
What is the best way to remove duplicate entries from a Data Table?
Do dtEmp on your current working DataTable:
DataTable distinctTable = dtEmp.DefaultView.ToTable( /*distinct*/ true);
It's nice.
Remove Duplicates
public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
{
Hashtable hTable = new Hashtable();
ArrayList duplicateList = new ArrayList();
//Add list of all the unique item value to hashtable, which stores combination of key, value pair.
//And add duplicate item value in arraylist.
foreach (DataRow drow in dTable.Rows)
{
if (hTable.Contains(drow[colName]))
duplicateList.Add(drow);
else
hTable.Add(drow[colName], string.Empty);
}
//Removing a list of duplicate items from datatable.
foreach (DataRow dRow in duplicateList)
dTable.Rows.Remove(dRow);
//Datatable which contains unique records will be return as output.
return dTable;
}
Here Links below
http://www.dotnetspider.com/resources/4535-Remove-duplicate-records-from-table.aspx
http://www.dotnetspark.com/kb/94-remove-duplicate-rows-value-from-datatable.aspx
For remove duplicates in column
http://dotnetguts.blogspot.com/2007/02/removing-duplicate-records-from.html
A simple way would be:
var newDt= dt.AsEnumerable()
.GroupBy(x => x.Field<int>("ColumnName"))
.Select(y => y.First())
.CopyToDataTable();
This post is regarding fetching only Distincts rows from Data table on basis of multiple Columns.
Public coid removeDuplicatesRows(DataTable dt)
{
DataTable uniqueCols = dt.DefaultView.ToTable(true, "RNORFQNo", "ManufacturerPartNo", "RNORFQId", "ItemId", "RNONo", "Quantity", "NSNNo", "UOMName", "MOQ", "ItemDescription");
}
You need to call this method and you need to assign value to datatable.
In Above code we have RNORFQNo , PartNo,RFQ id,ItemId, RNONo, QUantity, NSNNO, UOMName,MOQ, and Item Description as Column on which we want distinct values.
Heres a easy and fast way using AsEnumerable().Distinct()
private DataTable RemoveDuplicatesRecords(DataTable dt)
{
//Returns just 5 unique rows
var UniqueRows = dt.AsEnumerable().Distinct(DataRowComparer.Default);
DataTable dt2 = UniqueRows.CopyToDataTable();
return dt2;
}
/* To eliminate Duplicate rows */
private void RemoveDuplicates(DataTable dt)
{
if (dt.Rows.Count > 0)
{
for (int i = dt.Rows.Count - 1; i >= 0; i--)
{
if (i == 0)
{
break;
}
for (int j = i - 1; j >= 0; j--)
{
if (Convert.ToInt32(dt.Rows[i]["ID"]) == Convert.ToInt32(dt.Rows[j]["ID"]) && dt.Rows[i]["Name"].ToString() == dt.Rows[j]["Name"].ToString())
{
dt.Rows[i].Delete();
break;
}
}
}
dt.AcceptChanges();
}
}
There is a simple way using Linq GroupBy Method.
var duplicateValues = dt.AsEnumerable()
.GroupBy(row => row[0])
.Where(group => (group.Count() == 1 || group.Count() > 1))
.Select(g => g.Key);
foreach (var d in duplicateValues)
Console.WriteLine(d);
See more at: http://www.dotnetlines.com/Blogs/tabid/85/EntryId/49/Remove-duplicate-rows-from-a-DataTable-using-LINQ.aspx
Completely distinct rows:
public static DataTable Dictinct(this dt) => dt.DefaultView.ToTable(true);
Distinct by particular row(s) (Note that the columns mentioned in "distinctCulumnNames" will be returned in resulting DataTable):
public static DataTable Dictinct(this dt, params string[] distinctColumnNames) =>
dt.DefaultView.ToTable(true, distinctColumnNames);
Distinct by particular column (preserves all columns in given DataTable):
public static void Distinct(this DataTable dataTable, string distinctColumnName)
{
var distinctResult = new DataTable();
distinctResult.Merge(
.GroupBy(row => row.Field<object>(distinctColumnName))
.Select(group => group.First())
.CopyToDataTable()
);
if (distinctResult.DefaultView.Count < dataTable.DefaultView.Count)
{
dataTable.Clear();
dataTable.Merge(distinctResult);
dataTable.AcceptChanges();
}
}
You can use the DefaultView.ToTable method of a DataTable to do the filtering like this (adapt to C#):
Public Sub RemoveDuplicateRows(ByRef rDataTable As DataTable)
Dim pNewDataTable As DataTable
Dim pCurrentRowCopy As DataRow
Dim pColumnList As New List(Of String)
Dim pColumn As DataColumn
'Build column list
For Each pColumn In rDataTable.Columns
pColumnList.Add(pColumn.ColumnName)
Next
'Filter by all columns
pNewDataTable = rDataTable.DefaultView.ToTable(True, pColumnList.ToArray)
rDataTable = rDataTable.Clone
'Import rows into original table structure
For Each pCurrentRowCopy In pNewDataTable.Rows
rDataTable.ImportRow(pCurrentRowCopy)
Next
End Sub
In order to distinct all datatable columns, you can easily retrieve the names of the columns in a string array
public static DataTable RemoveDuplicateRows(this DataTable dataTable)
{
List<string> columnNames = new List<string>();
foreach (DataColumn col in dataTable.Columns)
{
columnNames.Add(col.ColumnName);
}
return dataTable.DefaultView.ToTable(true, columnNames.Select(c => c.ToString()).ToArray());
}
As you can notice, I thought of using it as an extension to DataTable class
I would prefer this as this is faster than DefaultView.ToTable and foreach loop to remove duplicates. Using this, we can have group by on multiple columns as well.
DataTable distinctDT = (from rows in dt.AsEnumerable()
group rows by new { ColA = rows["ColA"], ColB = rows["ColB"]} into grp
select grp.First()).CopyToDataTable();
I have the following:
//a datatable with some rows and columns lets say 5x5
var datatable = new DataTable();
var numberofrows = datatable.rows.count;
for (int i = 0; i < numberofrows; i++) {
//for each row, get the 3rd column
var cell = datatable.rows[i].???
}
how do I get the 3rd column for each row?
for 3rd column
var cellValue = datatable.Rows[i][2];
better, if you know the column name,
var cellValue = datatable.Rows[i]["column_name"];
If the table contains 2 columns "Property" and "Value". Contents can be inserted as follows
table.Columns.Add("Property", typeof(string));
table.Columns.Add("Value", typeof(string));
table.Rows.Add("P1", "abc");
table.Rows.Add("P2", "xyz");
To retrive contents of specific column
foreach (DataRow row in table.Rows)
{
if (row["Property"].ToString() == "P1")
{
var value = row["Value"].ToString();
}
}
we can read the particular column values by like this
foreach (DataTable table in ds.Tables)
{
if (table.TableName == "Table1")
{
for (int j = 0; j < table.Rows.Count; j++)
{
int a = Convert.ToInt32( table.Rows[j].ItemArray[3]);
int b = Convert.ToInt32(table.Rows[j].ItemArray[4]);
}
}
}
You can iterate thru the datatable and get every row, which can be thought as an array, so you can pick each element of that particular row using an index (and can also use the name of the column instead of the index, i.e.: row["column3 name"]).
foreach(DataRow row in datatable)
{
Console.WriteLine(row[2]);
}
I am trying to find a fast way to find a string in all datatable columns!
Followed is not working as I want to search within all columns value.
string str = "%whatever%";
foreach (DataRow row in dataTable.Rows)
foreach (DataColumn col in row.ItemArray)
if (row[col].ToString() == str) return true;
You can use LINQ. It wouldn't be any faster, because you still need to look at each cell in case the value is not there, but it will fit in a single line:
return dataTable
.Rows
.Cast<DataRow>()
.Any(r => r.ItemArray.Any(c => c.ToString().Contains("whatever")));
For searching for random text and returning an array of rows with at least one cell that has a case-insensitive match, use this:
var text = "whatever";
return dataTable
.Rows
.Cast<DataRow>()
.Where(r => r.ItemArray.Any(
c => c.ToString().IndexOf(text, StringComparison.OrdinalIgnoreCase) > 0
)).ToArray();
If you want to check every row of every column in your Datatable, try this (it works for me!).
DataTable YourTable = new DataTable();
// Fill your DataTable here with whatever you've got.
foreach (DataRow row in YourTable.Rows)
{
foreach (object item in row.ItemArray)
{
//Do what ya gotta do with that information here!
}
}
Don't forget to typecast object item to whatever you need (string, int etc).
I've stepped through with the debugger and it works a charm. I hope this helps, and good luck!
This can be achieved by filtering. Create a (re-usable) filtering string based on all the columns:
bool UseContains = false;
int colCount = MyDataTable.Columns.Count;
string likeStatement = (UseContains) ? " Like '%{0}%'" : " Like '{0}%'";
for (int i = 0; i < colCount; i++)
{
string colName = MyDataTable.Columns[i].ColumnName;
query.Append(string.Concat("Convert(", colName, ", 'System.String')", likeStatement));
if (i != colCount - 1)
query.Append(" OR ");
}
filterString = query.ToString();
Now you can get the rows where one of the columns matches your searchstring:
string currFilter = string.Format(filterString, searchText);
DataRow[] tmpRows = MyDataTable.Select(currFilter, somethingToOrderBy);
You can create a routine of search with an array of strings with the names of the columns, as well:
string[] elems = {"GUID", "CODE", "NAME", "DESCRIPTION"};//Names of the columns
foreach(string column in elems)
{
string expression = string.Format("{0} like '%{1}%'",column,
txtSearch.Text.Trim());//Search Expression
DataRow[] row = data.Select(expression);
if(row.Length > 0) {
// Some code here
} else {
// Other code here
}
}
You can get names of columns by using ColmunName Method. Then, you can search every column in DataTable by using them. For example, follwing code will work.
string str = "whatever";
foreach (DataRow row in dataTable.Rows)
{
foreach (DataColumn column in dataTable.Columns)
{
if (row[column.ColumnName.ToString()].ToString().Contains(str))
{
return true;
}
}
}
You can create a filter expression on the datatable as well. See this MSDN article. Use like in your filter expression.
string filterExp = "Status = 'Active'";
string sortExp = "City";
DataRow[] drarray;
drarray = dataSet1.Customers.Select(filterExp, sortExp, DataViewRowState.CurrentRows);
for (int i=0; i < drarray.Length; i++)
{
listBox1.Items.Add(drarray[i]["City"].ToString());
}
Let suppose there are three columns in my DataTable
code
name
color
If I know the code and name, how can I update the color of that specific row whose code and name match my criteria? I want to do this without using Loops!
You can use LINQ:
DataRow dr = datatable.AsEnumerable().Where(r => ((string)r["code"]).Equals(someCode) && ((string)r["name"]).Equals(someName)).First();
dr["color"] = someColor;
Of course I'm assuming all those criteria are strings. You should change the casts to the correct types.
// Use the Select method to find all rows matching the name and code.
DataRow[] rows = myDataTable.Select("name 'nameValue' AND code = 'codeValue');
for(int i = 0; i < rows.Length; i ++)
{
rows[i]["color"] = colorValue;
}
DataTable recTable = new DataTable();
// do stuff to populate table
recTable.Select(string.Format("[code] = '{0}' and [name] = '{1}'", someCode, someName)).ToList<DataRow>().ForEach(r => r["Color"] = colorValue);
With LINQ:
var dataRows = dt.AsEnumerable().Select(c => { c["color"] = c["Code"].ToString() == "1" ? "Red" : "White"; return c; });
dt = dataRows.CopyToDataTable();
You could do:
foreach (DataRow row in datatable.Rows)
{
if(row["code"].ToString() == someCode && row["name"].ToString() == someName)
{
row["color"] = someColor;
}
}
How can I get a sum for all the columns in a datatable? Say I had the following table. How can I calculate the "total" row? It should be easy to add total row to a datatable.
Columns hits uniques sigups, etc...
Rows
1 12 1 23
2 1 0 5
3 6 2 9
total 19 3 37
Update
I ended up with this. It was the only thing I could get to work.
For Each col As DataColumn In TotalsTable.Columns
If col.DataType.Name = "DateTime" Then
count = count + 1
Continue For
End If
Dim colTotal As Double = 0
Dim value As Double
For Each row As DataRow In TotalsTable.Rows
If Double.TryParse(row(col), value) Then
colTotal += Double.Parse(row(col))
End If
Next
totalRow(count) = colTotal
count = count + 1
Next
There is also a way to do this without loops using the DataTable.Compute Method. The following example comes from that page. You can see that the code used is pretty simple.:
private void ComputeBySalesSalesID(DataSet dataSet)
{
// Presumes a DataTable named "Orders" that has a column named "Total."
DataTable table;
table = dataSet.Tables["Orders"];
// Declare an object variable.
object sumObject;
sumObject = table.Compute("Sum(Total)", "EmpID = 5");
}
I must add that if you do not need to filter the results, you can always pass an empty string:
sumObject = table.Compute("Sum(Total)", "")
Try this:
DataTable dt = new DataTable();
int sum = 0;
foreach (DataRow dr in dt.Rows)
{
foreach (DataColumn dc in dt.Columns)
{
sum += (int)dr[dc];
}
}
I doubt that this is what you want but your question is a little bit vague
Dim totalCount As Int32 = DataTable1.Columns.Count * DataTable1.Rows.Count
If all your columns are numeric-columns you might want this:
You could use DataTable.Compute to Sum all values in the column.
Dim totalCount As Double
For Each col As DataColumn In DataTable1.Columns
totalCount += Double.Parse(DataTable1.Compute(String.Format("SUM({0})", col.ColumnName), Nothing).ToString)
Next
After you've edited your question and added more informations, this should work:
Dim totalRow = DataTable1.NewRow
For Each col As DataColumn In DataTable1.Columns
totalRow(col.ColumnName) = Double.Parse(DataTable1.Compute("SUM(" & col.ColumnName & ")", Nothing).ToString)
Next
DataTable1.Rows.Add(totalRow)
You can loop through the DataColumn and DataRow collections in your DataTable:
// Sum rows.
foreach (DataRow row in dt.Rows) {
int rowTotal = 0;
foreach (DataColumn col in row.Table.Columns) {
Console.WriteLine(row[col]);
rowTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("row total: {0}", rowTotal);
}
// Sum columns.
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
Console.WriteLine(row[col]);
colTotal += Int32.Parse(row[col].ToString());
}
Console.WriteLine("column total: {0}", colTotal);
}
Beware: The code above does not do any sort of checking before casting an object to an int.
EDIT: add a DataRow displaying the column sums
Try this to create a new row to display your column sums:
DataRow totalsRow = dt.NewRow();
foreach (DataColumn col in dt.Columns) {
int colTotal = 0;
foreach (DataRow row in col.Table.Rows) {
colTotal += Int32.Parse(row[col].ToString());
}
totalsRow[col.ColumnName] = colTotal;
}
dt.Rows.Add(totalsRow);
This approach is fine if the data type of any of your DataTable's DataRows are non-numeric or if you want to inspect the value of each cell as you sum. Otherwise I believe #Tim's response using DataTable.Compute is a better.
It's a pity to use .NET and not use collections and lambda to save your time and code lines
This is an example of how this works:
Transform yourDataTable to Enumerable, filter it if you want , according a "FILTER_ROWS_FIELD" column, and if you want, group your data by a "A_GROUP_BY_FIELD".
Then get the count, the sum, or whatever you wish.
If you want a count and a sum without grouby don't group the data
var groupedData = from b in yourDataTable.AsEnumerable().Where(r=>r.Field<int>("FILTER_ROWS_FIELD").Equals(9999))
group b by b.Field<string>("A_GROUP_BY_FIELD") into g
select new
{
tag = g.Key,
count = g.Count(),
sum = g.Sum(c => c.Field<double>("rvMoney"))
};
for (int i=0;i<=dtB.Columns.Count-1;i++)
{
array(0, i) = dtB.Compute("SUM([" & dtB.Columns(i).ColumnName & "])", "")
}