I have a DataTable which is like this -
EmpId,Country
1,Germany
2,Germany
3,UK
4,UK
5,UK
6,France
7,USA
8,USA
I want to group by Country and extract all groups into separate datatables. So, we
will have 4 groups/data tables. How do I do this ?
Stackoverflow won't let me paste fully working code. So here it is, thanks to
#Myles B. Currie
Tested code -
public void main()
{
DataSet ds = (DataSet) Dts.Variables["obj_Rs"].Value;
DataTable dt = ds.Tables[0];
List<DataTable> allCountryTables = new List<DataTable>();
DataView view = new DataView(dt);
DataTable distinctValues = view.ToTable(true, "Country");
//Create new DataTable for each of the distinct countries
//identified and add to allCountryTables list
foreach (DataRow row in distinctValues.Rows)
{
//Remove filters on view
view.RowFilter = String.Empty;
//get distinct country name
String country = row["Country"].ToString();
//filter view for that country
view.RowFilter = "Country = " + "'" + country + "'";
//export filtered view to new datatable
DataTable countryTable = view.ToTable();
//add new datatable to allCountryTables
allCountryTables.Add(countryTable);
}//for each
foreach(DataTable tbl in allCountryTables){
String table = getDataTable(tbl);
MessageBox.Show(table);
}//for
}//main
public static string getDataTable(DataTable dt){
string table = "";
foreach (DataRow dataRow in dt.Rows)
{
foreach (var item in dataRow.ItemArray)
{
table = table + item.ToString() + "|";
}//for
table = table + Environment.NewLine;
}//for
return table;
}//method
Certainly not the shortest method of doing this but since you are saying you are having .Net version issues this is a long way to get the job done. (Below code is untested)
DataTable table; //Your Datatable
List<DataTable> allCountryTables = new List<DataTable>();
//Get distinct countries from table
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "Country");
//Create new DataTable for each of the distinct countries identified and add to allCountryTables list
foreach (DataRow row in distinctValues.Rows)
{
//Remove filters on view
view.RowFilter = String.Empty;
//get distinct country name
String country = row["Country"].ToString());
//filter view for that country
view.RowFilter = "Country = " + country;
//export filtered view to new datatable
DataTable countryTable = view.ToTable();
//add new datatable to allCountryTables
allCountryTables.Add(countryTable);
}
This should do the job:
var countryGroups = dataTable.AsEnumerable()
.GroupBy(row => row.Field<string>("Country"));
Please remember about adding the following references:
System.Data.DataSetExtensions
You can use LINQ to create a subset of DataTables for every country:
Dim groups = From row In tblEmp
Let country = row.Field(Of String)("Country")
Group row By country Into Group
Select Group.CopyToDataTable()
Dim allCountryTables = groups.ToList()
Whoops, i was certain that there was a VB.NET tag....
var groups = from row in tblEmp.AsEnumerable()
let country = row.Field<string>("Country")
group row by country into Group
select Group.CopyToDataTable();
List<DataTable> allCountryTables = groups.ToList();
Related
I have datatable on which I have to perform filter like where, order by. I have list of customerName. I want to filter data for each customername
I tried below code for same
foreach (string customer in CustName)
{
Datarow[] DataDR = TradeFinanceBF3.Select(TradeFinanceBF3.Columns["Cust_Name"].ColumnName.Trim() + "='A'", "USD equi DESC");
}
I get datarow, then how to pass it to dataTable, and how to pass all customer data to same datatable.
I tried LinkQuery Also to filter data as below
foreach (string customer in CustName)
{
DataTable selectedTable = TradeFinanceBF3.AsEnumerable()
.Where(r => r.Field<string>("Cust_Name") == customer)
.OrderByDescending(r => r.Field<double>("IndexABC"))
.CopyToDataTable();
///Datable OutPut= ?????
}
I got datatable, But then how to add all customer data to one datatable?
You could do something like this:
DataRow[] result = TradeFinanceBF3.Select("Cust_Name ='A'", "USD equi DESC");
DataTable aux = TradeFinanceBF3.Clone();
foreach (DataRow record in result)
{
aux.ImportRow(record);
}
I hope it will fix your issue
[Test]
public void GetCustomerData()
{
DataTable TradeFinanceBF3 = GetTable();
DataTable NewDatatable = TradeFinanceBF3.Clone();
IList<string> CustName = new List<string> { "Janet", "David" };
var selectedTable = (from dataRow in TradeFinanceBF3.AsEnumerable()
join customerName in CustName on dataRow.Field<string>("Cust_Name") equals customerName
select new
{
CustName = dataRow["Cust_Name"],
IndexABC = dataRow["IndexABC"]
}).OrderByDescending(p=>p.IndexABC);
foreach (var table in selectedTable)
{
NewDatatable.Rows.Add(table.CustName, table.IndexABC);
}
Console.Write(NewDatatable);
}
private DataTable GetTable()
{
// Here we create a DataTable with four columns.
DataTable table = new DataTable();
table.Columns.Add("Cust_Name", typeof(string));
table.Columns.Add("IndexABC", typeof(double));
// Here we add five DataRows.
table.Rows.Add("David", 1);
table.Rows.Add("Sam", 2);
table.Rows.Add("Christoff",2);
table.Rows.Add("Janet", 4);
table.Rows.Add("Melanie", 6);
return table;
}
I have a DataTable that must be sorted, however i want to return a particular row as the last row even after sorting the DataTable. I will identify this row by a string value in a partiucular column.
public DataTable StandardReport3B(string missionId, string reportType, string startDate, string endDate)
{
List<long> missionIdList = new List<long>();
string[] missionIds = missionId.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string mission in missionIds)
{
missionIdList.Add(Convert.ToInt64(mission));
}
DataTable dt = new DataTable();
object reportData = null;
using (var ctx = new MedicalServiceEntities())
{
reportData = ctx.GetData(startDate, endDate, missionId).ToList();
}
dt = this.GenericListToDataTable(reportData);
DataView dv = dt.DefaultView;
dv.Sort = dt.Columns[0].ColumnName + " Asc";
return dv.ToTable();
}
You can use LINQ-to-DataSet:
dt = dt.AsEnumerable()
.OrderBy(r => r.Field<string>(0) == "Special Value")
.ThenBy(r => r.Field<string>(0))
.CopyToDataTable();
That works because the comparison returns either true or false and false is "lower".
In case someone just wants to know how to move the row in the table to another index as the title suggests: Add data row to datatable at predefined index
I will identify this row by a string value in a partiucular column.
What about:
dv.Sort = "ParticularColumn ASC, " + dt.Columns[0].ColumnName + " ASC">
Where "ParticularColumn" is a column with an identical, low value for all rows except the one you want to be last - and this row has a higher value.
I have a delete method, it gets an array of GUIDs and I have a data table... how can I filter the data table so it will only contain thoes GUIDs?
public void delete(Guid[] guidlist)
{
datatable template = ReadTemplateList()
...
}
Thank you!
With Linq to DataSet you can create new DataTable which will have only rows with those Guids:
public void Delete(Guid[] guids)
{
DataTable table = ReadTemplateList()
.AsEnumerable()
.Where(r => guids.Contains(r.Field<Guid>("ColumnName")))
.CopyToDataTable();
// ...
}
Another option (which also will work on old .NET versions) is filtering your table with built-in RowFilter functionality which supports IN filters. Let's assume you are filtering by column named ID:
// Check if guids.Length > 0
StringBuilder filter = new StringBuilder("ID IN (");
foreach (Guid id in guids)
filter.AppendFormat("Convert('{0}','System.Guid'),", id);
filter.Append(")");
DataTable template = ReadTemplateList();
DataView view = template.DefaultView;
view.RowFilter = filter.ToString();
DataTable table = view.ToTable();
You can use LINQ:
public static DataTable DeleteGuidsFromTemplate(Guid[] guidlist)
{
DataTable template = ReadTemplateList();
var rowsWithGuids = from row in template.AsEnumerable()
join guid in guidlist
on row.Field<Guid>("Guid") equals guid
select row;
return rowsWithGuids.CopyToDataTable();
}
If you can't use LINQ since you're lower than NET 3.5:
public static DataTable DeleteGuidsFromTemplate(Guid[] guidlist)
{
DataTable template = ReadTemplateList();
DataTable templateGuids = template.Clone();
foreach(DataRow row in template.Rows)
{
Guid guid = (Guid)row["Guid"];
int index = Array.IndexOf(guidlist, guid);
if (index >= 0)
templateGuids.ImportRow(row);
}
return templateGuids;
}
A solution based on DataTable and DataRows.
//fill the datatable from back end
string connStr = ConfigurationManager.ConnectionStrings["ConsoleApplication1.Properties.Settings.NORTHWNDConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand comm = new SqlCommand("select categoryid,categoryname from Categories order by categoryname");
comm.Connection = conn;
SqlDataReader dr = comm.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
//datatable filter logic
string[] filter = { "1", "2" };
DataTable filteredTable = dt.Clone();
foreach (string str in filter)
{
DataRow[] filteredRows = dt.Select("categoryid="+ str); //search for categoryID
foreach (DataRow dtr in filteredRows)
{
filteredTable.ImportRow(dtr);
}
}
EDIT
Without going in the for loop
DataTable dt = new DataTable();
dt.Load(dr); //fill the datatable with sqldatareader
DataTable filteredTable = dt.Clone();
DataView dv = dt.DefaultView;
dv.RowFilter = "categoryid in (1,2)";
filteredTable = dv.ToTable();
We have two columns in a DataTable, like so:
COL1 COL2
Abc 5
Def 8
Ghi 3
We're trying to sort this datatable based on COL2 in decreasing order.
COL1 COL2
ghi 8
abc 4
def 3
jkl 1
We tried this:
ft.DefaultView.Sort = "COL2 desc";
ft = ft.DefaultView.ToTable(true);
but, without using a DataView, we want to sort the DataTable itself, not the DataView.
I'm afraid you can't easily do an in-place sort of a DataTable like it sounds like you want to do.
What you can do is create a new DataTable from a DataView that you create from your original DataTable. Apply whatever sorts and/or filters you want on the DataView and then create a new DataTable from the DataView using the DataView.ToTable method:
DataView dv = ft.DefaultView;
dv.Sort = "occr desc";
DataTable sortedDT = dv.ToTable();
This will help you...
DataTable dt = new DataTable();
dt.DefaultView.Sort = "Column_name desc";
dt = dt.DefaultView.ToTable();
Its Simple Use .Select function.
DataRow[] foundRows=table.Select("Date = '1/31/1979' or OrderID = 2", "CompanyName ASC");
DataTable dt = foundRows.CopyToDataTable();
And it's done......Happy Coding
Maybe the following can help:
DataRow[] dataRows = table.Select().OrderBy(u => u["EmailId"]).ToArray();
Here, you can use other Lambda expression queries too.
Or, if you can use a DataGridView, you could just call Sort(column, direction):
namespace Sorter
{
using System;
using System.ComponentModel;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.dataGridView1.Rows.Add("Abc", 5);
this.dataGridView1.Rows.Add("Def", 8);
this.dataGridView1.Rows.Add("Ghi", 3);
this.dataGridView1.Sort(this.dataGridView1.Columns[1],
ListSortDirection.Ascending);
}
}
}
Which would give you the desired result:
Did you try using the Select(filterExpression, sortOrder) method on DataTable? See here for an example. Note this method will not sort the data table in place, if that is what you are looking for, but it will return a sorted array of rows without using a data view.
table.DefaultView.Sort = "[occr] DESC";
Use LINQ - The beauty of C#
DataTable newDataTable = baseTable.AsEnumerable()
.OrderBy(r=> r.Field<int>("ColumnName"))
.CopyToDataTable();
There is 2 way for sort data
1) sorting just data and fill into grid:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
DataTable dt2 = new DataTable(); // temp data table
DataRow[] dra = dt1.Select("", "ID DESC");
if (dra.Length > 0)
dt2 = dra.CopyToDataTable();
datagridview1.DataSource = dt2;
2) sort default view that is like of sort with grid column header:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
dt1.DefaultView.Sort = "ID DESC";
datagridview1.DataSource = dt1;
It turns out there is a special case where this can be achieved. The trick is when building the DataTable, collect all the rows in a list, sort them, then add them. This case just came up here.
//Hope This will help you..
DataTable table = new DataTable();
//DataRow[] rowArray = dataTable.Select();
table = dataTable.Clone();
for (int i = dataTable.Rows.Count - 1; i >= 0; i--)
{
table.ImportRow(dataTable.Rows[i]);
}
return table;
TL;DR
use tableObject.Select(queryExpression, sortOrderExpression) to select data in sorted manner
Complete example
Complete working example - can be tested in a console application:
using System;
using System.Data;
namespace A
{
class Program
{
static void Main(string[] args)
{
DataTable table = new DataTable("Orders");
table.Columns.Add("OrderID", typeof(Int32));
table.Columns.Add("OrderQuantity", typeof(Int32));
table.Columns.Add("CompanyName", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
DataRow newRow = table.NewRow();
newRow["OrderID"] = 1;
newRow["OrderQuantity"] = 3;
newRow["CompanyName"] = "NewCompanyName";
newRow["Date"] = "1979, 1, 31";
// Add the row to the rows collection.
table.Rows.Add(newRow);
DataRow newRow2 = table.NewRow();
newRow2["OrderID"] = 2;
newRow2["OrderQuantity"] = 2;
newRow2["CompanyName"] = "NewCompanyName1";
table.Rows.Add(newRow2);
DataRow newRow3 = table.NewRow();
newRow3["OrderID"] = 3;
newRow3["OrderQuantity"] = 2;
newRow3["CompanyName"] = "NewCompanyName2";
table.Rows.Add(newRow3);
DataRow[] foundRows;
Console.WriteLine("Original table's CompanyNames");
Console.WriteLine("************************************");
foundRows = table.Select();
// Print column 0 of each returned row.
for (int i = 0; i < foundRows.Length; i++)
Console.WriteLine(foundRows[i][2]);
// Presuming the DataTable has a column named Date.
string expression = "Date = '1/31/1979' or OrderID = 2";
// string expression = "OrderQuantity = 2 and OrderID = 2";
// Sort descending by column named CompanyName.
string sortOrder = "CompanyName ASC";
Console.WriteLine("\nCompanyNames data for Date = '1/31/1979' or OrderID = 2, sorted CompanyName ASC");
Console.WriteLine("************************************");
// Use the Select method to find all rows matching the filter.
foundRows = table.Select(expression, sortOrder);
// Print column 0 of each returned row.
for (int i = 0; i < foundRows.Length; i++)
Console.WriteLine(foundRows[i][2]);
Console.ReadKey();
}
}
}
Output
try this:
DataTable DT = new DataTable();
DataTable sortedDT = DT;
sortedDT.Clear();
foreach (DataRow row in DT.Select("", "DiffTotal desc"))
{
sortedDT.NewRow();
sortedDT.Rows.Add(row);
}
DT = sortedDT;
Yes the above answers describing the corect way to sort datatable
DataView dv = ft.DefaultView;
dv.Sort = "occr desc";
DataTable sortedDT = dv.ToTable();
But in addition to this, to select particular row in it you can use LINQ and try following
var Temp = MyDataSet.Tables[0].AsEnumerable().Take(1).CopyToDataTable();
I want to convert dataview rowfilter value to datatable. I have a dataset with value. Now i was filter the value using dataview. Now i want to convert dataview filter values to datatable.please help me to copy it........
My partial code is here:
DataSet5TableAdapters.sp_getallempleaveTableAdapter TA = new DataSet5TableAdapters.sp_getallempleaveTableAdapter();
DataSet5.sp_getallempleaveDataTable DS = TA.GetData();
if (DS.Rows.Count > 0)
{
DataView datavw = new DataView();
datavw = DS.DefaultView;
datavw.RowFilter = "fldempid='" + txtempid.Text + "' and fldempname='" + txtempname.Text + "'";
if (datavw.Count > 0)
{
DT = datavw.Table; // i want to copy dataview row filter value to datatable
}
}
please help me...
You can use
if (datavw.Count > 0)
{
DT = datavw.ToTable(); // This will copy dataview's RowFilterd values to datatable
}
You can use DateView.ToTable() for converting the filtered dataview in to a datatable.
DataTable DTb = new DataTable();
DTb = SortView.ToTable();
The answer does not work for my situation because I have columns with expressions. DataView.ToTable() will only copy the values, not the expressions.
First I tried this:
//clone the source table
DataTable filtered = dt.Clone();
//fill the clone with the filtered rows
foreach (DataRowView drv in dt.DefaultView)
{
filtered.Rows.Add(drv.Row.ItemArray);
}
dt = filtered;
but that solution was very slow, even for just 1000 rows.
The solution that worked for me is:
//create a DataTable from the filtered DataView
DataTable filtered = dt.DefaultView.ToTable();
//loop through the columns of the source table and copy the expression to the new table
foreach (DataColumn dc in dt.Columns)
{
if (dc.Expression != "")
{
filtered.Columns[dc.ColumnName].Expression = dc.Expression;
}
}
dt = filtered;
The below code is for Row filter from Dataview and the result converted in DataTable
itemCondView.RowFilter = "DeliveryNumber = '1001'";
dataSet = new DataSet();
dataSet.Tables.Add(itemCondView.ToTable());