How to add row with value to existing datatable in console Application - c#

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

Related

How to cut DataTable's Columns by using a string array?

I have a DataTable. How to cut out its columns, and return a new DataTable?
I'm trying to create a method with the following parameters:
DataTable dt.
A string Array containing some fields.
It should look something like this:
public static DataTable cutDataTable(DataTable dt, List<string> fileds)
{
DataTable newDt = null;
// processing code...
return newDt
}
No exceptions.
You could make use of DataView.ToTable method for the purpose. For example,
var fields = new []{"Age","Id"}; //Fields to be selected.
var result = new DataView(table).ToTable(false, fields);
This would return a new DataTable from the source table with only the specified fields.
If I understand you correctly, you are trying to do something like this:
public static DataTable CutDataTable(DataTable dt, IList<string> columnsToRemove,
bool keepData = true)
{
DataTable newDt = (keepData ? dt.Copy() : dt.Clone());
foreach (string colName in columnsToRemove)
{
if (!newDt.Columns.Contains(colName)) continue;
newDt.Columns.Remove(colName);
}
return newDt;
}
Usage:
var dt = new DataTable();
dt.Columns.Add("Column1");
dt.Columns.Add("Column2");
dt.Columns.Add("Column3");
dt.Columns.Add("Column4");
dt.Rows.Add("1", "2", "3", "4");
var newDt = CutDataTable(dt, new[] { "Column3", "Column4" });
Console.WriteLine("New column count = " + newDt.Columns.Count);
Console.WriteLine("First row data: " + string.Join(",", newDt.Rows[0].ItemArray));
Output:
New column count = 2
First row data: 1,2

Get N number of columns from datatable c#

I have a datatable where I need to take n number of columns. For ex: From the below datatable I need to take first 10 columns alone with data and put it in another datatable.
Code:
DataTable dtRecord = DAL.GetRecords();
I tried this and this doesn't take the required column.
var selectColumns = dtRecord .Columns.Cast<System.Data.DataColumn>().Take(10);
You can also use this
private DataTable GetNColumnsFromDataTable(DataTable tblSource, int outputCols)
{
DataTable columnOutput = tblSource.Copy();
if (outputCols > 0 && outputCols < tblSource.Columns.Count)
{
while (outputCols < columnOutput.Columns.Count)
{
columnOutput.Columns.RemoveAt(columnOutput.Columns.Count - 1);
}
}
return columnOutput;
}
You can do it like this:
var selectColumns = dtRecord.Columns.Cast<DataColumn>().Take(10);
var dtResult = new DataTable();
foreach (var column in selectColumns)
dtResult.Columns.Add(column.ColumnName);
foreach (DataRow row in dtRecord.Rows)
dtResult.Rows.Add(row.ItemArray.Take(10).ToArray());
Perhaps you should create a column of the same type and with the same expression:
dtResult.Columns.Add(column.ColumnName, column.DataType, column.Expression);
To copy from one DataTable to another, you can extract the columns of interest
var moveCols = dtRecord.Columns.Cast<DataColumn>().Take(10).Select(c => c.ColumnName).ToArray();
Then you must create new DataColumns in a new table, then create new DataRows in the new table:
var newTable = new DataTable();
foreach (var c in moveCols)
newTable.Columns.Add(c);
foreach (var r in dtRecord.AsEnumerable())
newTable.Rows.Add(moveCols.Select(c => r[c]).ToArray());
Which you can make an extension method on DataTable:
public static DataTable Slice(this DataTable dt, params string[] colnames) {
var newTable = new DataTable();
foreach (var c in colnames)
newTable.Columns.Add(c, dt.Columns[c].DataType);
foreach (var r in dt.AsEnumerable())
newTable.Rows.Add(colnames.Select(c => r[c]).ToArray());
return newTable;
}
Now you can call
var newTable = dtRecord.Slice(moveCols);
With a nice extension method, you can convert from Dictionarys to a DataTable dynamically:
var newTable = dtRecord.AsEnumerable().Select(r => moveCols.ToDictionary(c => c, c => r[c])).AsDataTable();
I have some for converting ExpandoObject and anonymous objects as well, as well as an extension to convert those to anonymous objects dynamically. Here is the code for Dictionarys to DataTable:
public static DataTable AsDataTable(this IEnumerable<IDictionary<string, object>> rows) {
var dt = new DataTable();
if (rows.Count() > 0) {
foreach (var kv in rows.First())
dt.Columns.Add(kv.Key, kv.Value.GetType());
foreach (var r in rows)
dt.Rows.Add(r.Values.ToArray());
}
return dt;
}
public static DataTable AsDataTable(this IEnumerable<Dictionary<string, object>> rows) => ((IEnumerable<IDictionary<string, object>>)rows).AsDataTable();
Get 10 columns:
var tbl = new System.Data.DataTable();
var cols = tbl.Columns.Cast<System.Data.DataColumn>().Take(10);
// if you wish to get first 10 columns...
If you want to get the data, then you have to loop through the columns to get the data.
var data = cols.SelectMany(x => tbl.Rows.Cast().Take(10).Select(y => y[x]));
of course, this will dump all the data into an ienumerable, if you want to use strong typed object or a list of one dimensional array, believe it's fairly simple, for example:
var data2 = cols.Select(x => tbl.Rows.Cast().Take(10).Select(y => y[x]).ToArray());

Group a DataTable into separate DataTables?

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

filter a data table with values from an array c#

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

How to 'union' 2 or more DataTables in C#?

How to 'union' 2 or more DataTables in C#?
Both table has same structure.
Is there any build-in function or should we do manually?
You are looking most likely for the DataTable.Merge method.
Example:
private static void DemonstrateMergeTable()
{
DataTable table1 = new DataTable("Items");
// Add columns
DataColumn idColumn = new DataColumn("id", typeof(System.Int32));
DataColumn itemColumn = new DataColumn("item", typeof(System.Int32));
table1.Columns.Add(idColumn);
table1.Columns.Add(itemColumn);
// Set the primary key column.
table1.PrimaryKey = new DataColumn[] { idColumn };
// Add RowChanged event handler for the table.
table1.RowChanged += new
System.Data.DataRowChangeEventHandler(Row_Changed);
// Add ten rows.
DataRow row;
for (int i = 0; i <= 9; i++)
{
row = table1.NewRow();
row["id"] = i;
row["item"] = i;
table1.Rows.Add(row);
}
// Accept changes.
table1.AcceptChanges();
PrintValues(table1, "Original values");
// Create a second DataTable identical to the first.
DataTable table2 = table1.Clone();
// Add column to the second column, so that the
// schemas no longer match.
table2.Columns.Add("newColumn", typeof(System.String));
// Add three rows. Note that the id column can't be the
// same as existing rows in the original table.
row = table2.NewRow();
row["id"] = 14;
row["item"] = 774;
row["newColumn"] = "new column 1";
table2.Rows.Add(row);
row = table2.NewRow();
row["id"] = 12;
row["item"] = 555;
row["newColumn"] = "new column 2";
table2.Rows.Add(row);
row = table2.NewRow();
row["id"] = 13;
row["item"] = 665;
row["newColumn"] = "new column 3";
table2.Rows.Add(row);
// Merge table2 into the table1.
Console.WriteLine("Merging");
table1.Merge(table2, false, MissingSchemaAction.Add);
PrintValues(table1, "Merged With table1, schema added");
}
private static void Row_Changed(object sender,
DataRowChangeEventArgs e)
{
Console.WriteLine("Row changed {0}\t{1}", e.Action,
e.Row.ItemArray[0]);
}
private static void PrintValues(DataTable table, string label)
{
// Display the values in the supplied DataTable:
Console.WriteLine(label);
foreach (DataRow row in table.Rows)
{
foreach (DataColumn col in table.Columns)
{
Console.Write("\t " + row[col].ToString());
}
Console.WriteLine();
}
}
You could try this:
public static DataTable Union (DataTable First, DataTable Second)
{
//Result table
DataTable table = new DataTable("Union");
//Build new columns
DataColumn[] newcolumns = new DataColumn[First.Columns.Count];
for(int i=0; i < First.Columns.Count; i++)
{
newcolumns[i] = new DataColumn(
First.Columns[i].ColumnName, First.Columns[i].DataType);
}
table.Columns.AddRange(newcolumns);
table.BeginLoadData();
foreach(DataRow row in First.Rows)
{
table.LoadDataRow(row.ItemArray,true);
}
foreach(DataRow row in Second.Rows)
{
table.LoadDataRow(row.ItemArray,true);
}
table.EndLoadData();
return table;
}
From here (not tested).
You could use Concat from Linq to datasets (get the free chapter of LINQ in Action) to join them and then .AsDataTable to create the table (assuming you actually want them as a DataTable)
Stumbled across this question, and Ruben Bartelink gave a great answer, but with no code. So I had to look it up elsewhere, which defeats the point of StackOverflow. Now that it's 2010, the other answers given aren't quite as viable. For reference, here's code demonstrating the CopyToDataTable() extension method. It's in VB so as to not steal the credit from Ruben if he wants to revisit the past and post a more complete answer :)
Public Function GetSchema(ByVal dbNames As IEnumerable(Of String)) As DataTable
Dim schemaTables As New List(Of DataTable)()
For Each dbName As String In dbNames
Dim cnnStr = GetConnectionString(dbName)
Dim cnn As New SqlConnection(cnnStr)
cnn.Open()
Dim dt = cnn.GetSchema("Columns")
cnn.Close()
schemaTables.Add(dt)
Next
Dim dtResult As DataTable = Nothing
For Each dt As DataTable In schemaTables
If dtResult Is Nothing Then
dtResult = dt
Else
dt.AsEnumerable().CopyToDataTable(dtResult, LoadOption.PreserveChanges)
End If
Next
Return dtResult
End Function
Try this using Linq to DataSet, must add the reference for System.Data.DataSetExtensions.dll, another approach, alternative for DataTable.Merge method).
static void Main(string[] args)
{
DoUnion();
}
private static void DoUnion()
{
DataTable table1 = GetProducts();
DataTable table2 = NewProducts();
var tbUnion = table1.AsEnumerable()
.Union(table2.AsEnumerable());
DataTable unionTable = table1.Clone();
foreach (DataRow fruit in tbUnion)
{
var fruitValue = fruit.Field<string>(0);
Console.WriteLine("{0}->{1}", fruit.Table, fruitValue);
DataRow row = unionTable.NewRow();
row.SetField<string>(0, fruitValue);
unionTable.Rows.Add(row);
}
}
private static DataTable NewProducts()
{
DataTable table = new DataTable("CitricusTable");
DataColumn col = new DataColumn("product", typeof(string));
table.Columns.Add(col);
string[] citricusFruits = { "Orange", "Grapefruit", "Lemon", "Lime", "Tangerine" };
foreach (string fruit in citricusFruits)
{
DataRow row = table.NewRow();
row.SetField<string>(col, fruit);
table.Rows.Add(row);
}
return table;
}
private static DataTable GetProducts()
{
DataTable table = new DataTable("MultipleFruitsTable");
DataColumn col = new DataColumn("product", typeof(string));
table.Columns.Add(col);
string[] multipleFruits = { "Breadfruit", "Custardfruit", "Jackfruit", "Osage-orange", "Pineapple" };
foreach (string fruit in multipleFruits)
{
DataRow row = table.NewRow();
row.SetField<string>(col, fruit);
table.Rows.Add(row);
}
return table;
}
antonio

Categories