I have a datatable with 20 columns. But i don't need all the columns for the current processing except 5. So i did the below to remove the columns
List<string> clmnames = new List<string>() { "clm6","clm7"..."clm20" };
foreach (string dcName in clmnames)
{
TestAndRemoveColumn(dcName, ds.Tables["TestTable"]);
}
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataColumnCollection dcCollection = datatable.Columns;
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName);
}
}
Instead of looping through the 15 times is there any other way to achieve using easily ?
try this
List<string> listtoRemove = new List<string> { "CLM6", "CLM7", "CLM20" };
for (int i = dt.Columns.Count - 1; i >= 0; i--)
{
DataColumn dc = dt.Columns[i];
if (listtoRemove.Contains(dc.ColumnName.ToUpper()))
{
dt.Columns.Remove(dc);
}
}
In some scenarios may be preferable to clone DataTable and specify columns to copy.
DataView view = new DataView(table);
DataTable table2 = view.ToTable(false, "clm6", "clm7", ...);
Problem seems to be in your code, you get all the comlumns from the datatable then remove the columns but you have not again assign the columns to that datatable
first you get columns
DataColumnCollection dcCollection = datatable.Columns; // get cols
if (dcCollection.Contains(dcName))
{
dcCollection.Remove(dcName); /// remove columns
// but you have not updated you datatable columns.
here should be something like this
datatable.Columns = dcCollection; /// i don't know this will work or not check it
}
Try this
DataTable dt;
dt.Columns.Remove("columnName");
dt.Columns.RemoveAt(columnIndex);
you can use them as
private void TestAndRemoveColumn(string dcName,DataTable datatable)
{
DataTable dt = datatable;
dt.Columns.Remove("dcName");
}
Alternatively you can select only the required columns(Only 5 in your case) like this.
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Value");
dt.Rows.Add("1", "One");
dt.Rows.Add("2", "Two");
string[] arr= new string[1];
arr[0] = "Value";//add the required columns to the array
//return only the required columns.
DataTable dt2 = dt.DefaultView.ToTable(false, arr);
You could join the columns you want remove with the available columns:
var keepColNames = new List<String>(){ "clm5" };
var allColumns = tbl.Columns.Cast<DataColumn>();
var allColNames = allColumns.Select(c => c.ColumnName);
var removeColNames = allColNames.Except(keepColNames);
var colsToRemove = from r in removeColNames
join c in allColumns on r equals c.ColumnName
select c;
while (colsToRemove.Any())
tbl.Columns.Remove(colsToRemove.First());
If you know that you only have few remaining columns, you could add the column(s):
var colsToAdd = (from keepCol in keepColNames
join col in tbl.Columns.Cast<DataColumn>()
on keepCol equals col.ColumnName
select col).ToList();
tbl.Columns.Clear();
foreach (var colToAdd in colsToAdd)
tbl.Columns.Add(colToAdd);
Related
I have a DataGridView and I want to fill it with two different arrays. With my current code, I can only add one column to the DataGridView. If I try to add two arrays only the last one is displayed on the DataGridView.
DataTable info= new DataTable();
SqlDataAdapter db = new SqlDataAdapter(query, con);
db.Fill(info);
if (info.Rows.Count > 0)
{
string prods= info.Rows[0]["prods"].ToString();
string prices= info.Rows[0]["prices"].ToString();
string[] f1 = prods.Split(',');
string[] f2 = prices.Split(',');
dataGridView2.AutoGenerateColumns = true;
dataGridView2.DataSource = f1.Select(x => new { prods= x }).ToList();
dataGridView2.DataSource = f2.Select(y => new { prices= z }).ToList();
}
So why not just add the products as the datasource and then add a column for price which you can then populate:
dataGridView2.Columns.Add(new DataColumn("Prices", typeof(string)));
int i = 0;
foreach (string row in prods){
dataGridView2["Prices][i] = row;
i++;
}
I am trying to merge two data table dt and dt4. I want to merge 2 data tables, having different schemas, and no common identifier together. Becuase the first data table dt contains some values.I get dt count on x. Based on that count I have to fetch some value table and stored in dt4. if if dt contains 3 row value then x=3 and dt4 contains 3 values. After these process I have to merge dt and dt4 and displayed as one table.
While using the given below code getting one error. The error is : "'column' argument cannot be null." Help me to find a proper soluion. Thank you.
Code:
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[x+1]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == y)
{
i = 0;
}
}
DataTable dt4 = new DataTable();
dt4.Columns.Add("Team");
foreach (string s in strArr)
{
dt4.Rows.Add(s); // Converting string array strArr[] to data table dt4
}
dt.Merge(dt4); // error poppup here. Error : 'column' argument cannot be null.
GridView2.DataSource = dt;
GridView2.DataBind();
}
dt contain
State District SiteID SiteName
----- -------- ------ --------
Sate1 District1 1001 A
Sate2 District2 1002 B
Sate3 District3 1003 C
dt4 contain
Team
-----
Team1
Team2
Team3
I need a final output as:
State District SiteID SiteName Team
----- -------- ------ -------- -----
Sate1 District1 1001 A Team1
Sate2 District2 1002 B Team2
Sate3 District3 1003 C Team3
Do you have relationship. If you have primary key ID in First Table and you can add ID column in Second Table
See here MSDN Article Merge Datatables
If you add a relationship between the 2 datatables, like a common identifier - you would be able to extract the common columns between datatables automatically using Linq.
Something like the following;
var commonColumns = dt1.Columns.OfType<DataColumn>().Intersect(dt2.Columns.OfType<DataColumn>(), new DataColumnComparer());
DataTable result = new DataTable();
dt1.PrimaryKey = commonColumns.ToArray();
result.Merge(dt1, false, MissingSchemaAction.AddWithKey);
result.Merge(dt2, false, MissingSchemaAction.AddWithKey);
Have a look at a previous question about this Full outer join, on 2 data tables, with a list of columns
The given code is working perfectly. Thank you for all valuable comments.
Code :
protected void ddlCircle_SelectedIndexChanged(object sender, EventArgs e)
{
ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter cd;
cd = new ShadingAnalysisDataSetTableAdapters.tbl_CadEngineersTeamTableAdapter();
DataTable dt = new DataTable();
dt = cd.GetAvailableData(ddlCircle.SelectedValue); // Getting details of unassigned site
int x, y;
DataTable dt3 = new DataTable();
dt3 = cd.GetTeam();
y = dt3.Rows.Count;
x = dt.Rows.Count; // counting the unassinged sites
DataTable dt2 = new DataTable();
dt2 = cd.GetAssignTeam(x); //Getting team based on count
string[] arr = new string[dt2.Rows.Count];
int i = 0;
foreach (DataRow r in dt2.Rows)
{
arr[i] = r["Team"].ToString(); // assigning available team to array
i++;
}
string[] strArr = new string[x+1]; // another array to copy arr values.
i = 0; int j = 0;
while (j <= x)
{
strArr[j]= arr[i] ; // copying the arr[] values into strArr[] based on count.
i++;
j++;
if (i == y)
{
i = 0;
}
}
DataTable dt4 = new DataTable();
dt4.Columns.Add("Team");
foreach (string s in strArr)
{
dt4.Rows.Add(s); // Converting string array strArr[] to data table dt4
}
//Adding new data table for merging two table details
DataTable dt7 = new DataTable();
//create columns and copy data from dt:
dt7 = dt.Copy();
foreach (DataColumn column in dt4.Columns)
dt7.Columns.Add(column.ColumnName, typeof(string));
//copy data from dt4:
foreach (DataRow row in dt4.Rows)
{
dt7.Rows[dt4.Rows.IndexOf(row)][5] = row[0];
}
GridView3.DataSource = dt7;
GridView3.DataBind();
}
You don't have relationship with table dt and table dt4.
Problem::You are facing this error because you dont have any relation between these two data tables.
I think you better start by adding relationship first. If you have primary key ID in dt and you can add ID column in dt4 with the relevant ID.
So first create a column in both tables which is common and then on basis of that relationship
you can use DataTable.Merge method directly
I have data like this..
ID
1234-001
1234-002
1234-003
5678-001
7890-001
7890-002
I am holding this data in a datatable. I am attempting to do some processing on the rows by groups based on the base number i.e. 1234, 5678, 7890
How can I iterate through this datatable and hold in new (temp) datatable
1234-001,1234-002, 1234-003
clear the temp datatable then hold
5678-001
clear the temp datatable then hold
7890-001,7890-002
I am working on an old code base and LINQ is not available. I cant come up with an elegant solution. Maybe something to do with dataviews im not sure?
You say you don't want to use LINQ but would prefer an elegant solution... Unless I am missing something vital in your question, this LINQified code seems to let you do what you want.
var grouped = from d in data
group d by d.Id.Split('-').FirstOrDefault();
foreach(var g in grouped) {
// do something with each group
}
Non-LINQ, non-var answer:
DataTable data = new DataTable();
data.Columns.Add("ID");
data.Columns.Add("Value");
data.Rows.Add("1234-001", "Row 1");
data.Rows.Add("1234-002", "Row 2");
data.Rows.Add("1234-003", "Row 3");
data.Rows.Add("5678-001", "Row 4");
data.Rows.Add("7890-001", "Row 5");
data.Rows.Add("7890-002", "Row 5");
Dictionary<String, List<DataRow>> grouped = new Dictionary<String, List<DataRow>>();
foreach(DataRow r in data.Select()) {
List<DataRow> groupedRows;
String key = r["ID"].ToString().Split('-')[0];
if(!grouped.TryGetValue(key, out groupedRows)) {
groupedRows = new List<DataRow>();
grouped[key] = groupedRows;
}
groupedRows.Add(r);
}
foreach(KeyValuePair<String, List<DataRow>> g in grouped) {
String groupKey = g.Key;
Console.WriteLine(groupKey);
foreach(DataRow r in g.Value) {
Console.WriteLine("\t{0}", r["Value"]);
}
}
I get the following output, so I'm not seeing "it only groups the first 3 and stops":
1234
Row 1
Row 2
Row 3
5678
Row 4
7890
Row 5
Row 5
Here is a non Linq example. Since you say it's sorted you can do it in one loop.
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof (string));
dt1.Rows.Add("1234-001");
dt1.Rows.Add("1234-002");
dt1.Rows.Add("1234-003");
dt1.Rows.Add("5678-001");
dt1.Rows.Add("7890-001");
dt1.Rows.Add("7890-002");
int i = 0;
while (i < dt1.Rows.Count)
{
DataRow row = dt1.Rows[i];
string key = row.Field<string>("ID").Split('-')[0];
DataView dv = new DataView(dt1);
dv.RowFilter = String.Format("ID LIKE '{0}*'", key.Replace("'", "''"));
DataTable tempdt = dv.ToTable();
i = i + tempdt.Rows.Count;
}
Does this help some?
DataTable dt = new DataTable();
dt.Columns.Add("Data", typeof(string));
dt.Rows.Add("1234-001");
dt.Rows.Add("1234-002");
dt.Rows.Add("1234-003");
dt.Rows.Add("5678-001");
dt.Rows.Add("7890-001");
dt.Rows.Add("7890-002");
var stuff = from dr in dt.Select()
group dr by dr["Data"].ToString().Split('-')[0] into g
select new {First = g.Key, Records = g.ToList()};
stuff.Dump();
var groups = table.AsEnumerable();
List<List<DataRow>> groupList = (from g in table.AsEnumerable()
group g by g.Field<string>("id").ToString().Split('-').First() into Group1
select Group1.ToList()).ToList();
I already have an SQlite database setup. Right now I'm parsing through it. For example, if certain values in the column Seq are >30 I transfer those values to a list. I want to use that list, to populate a datagrid view so the user can see what values were > 30
How do I populate a data grid view with multiple lists? Basically column 1 should be list1, column 2, list 2, etc.
EDIT: DOES anyone think I should use a list view instead? If so, how?
Here's my code for parsing to obtain values for my lists. Now I need to somehow populate a DGV with these lists.
string sql4 = "select * from abc";
SQLiteCommand command = new SQLiteCommand(sql4, sqlite_conn);
// The datareader allows us to read the table abc row by row
SQLiteDataReader reader = command.ExecuteReader();
// What happens next: We are trying to parse each column for irregularities to show to the user. For example if a value in column
// Seq is >30, we need to let the user know. We do this by adding all values >30 to the SeqIrregularities list.
while (reader.Read())
{
int seq;
if (int.TryParse(reader["Seq"].ToString(), out seq))
if (seq > 30)
{
SeqIrregularities.Add(seq);
seq1 = true;
}
int maxlen;
if (int.TryParse(reader["MaxLen"].ToString(), out maxlen))
if (maxlen> 30.00)
{
MaxLen.Add(maxlen);
maxlen1 = true;
}
}
I'd create an adapter class to take your multiple lists and populate either a custom object or perhaps a datatable. Then you can bind that object as the datasource to your grid.
public DataTable ConvertListsToDatatable(List<int> list1, List<int> list2)
{
DataTable dt = new DataTable();
DataColumn column;
DataRow row;
// add the first column
column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.ColumnName = "List1Id";
dt.Columns.Add(column);
// add the second column
column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.ColumnName = "List2Id";
dt.Columns.Add(column);
int i = 0;
while ((list1 != null)&&(i < list1.Count) || (list2 != null)&&(i < list2.Count))
{
row = dt.NewRow();
if (list1 != null)
{
if (i < list1.Count)
{
row["List1Id"] = List1[i];
}
}
if (list2 != null)
{
if (i < list2.Count)
{
row["List2Id"] = List2[i];
}
}
dt.Rows.Add(row);
i++;
}
return dt;
}
Don't bother making lists in the first place. Just load a table directly.
DataTable myData = new DataTable();
DataColumn seqCol = new DataColumn("Seq", typeof (int));
DataColumn maxLenCol = new DataColumn("MaxLen", typeof (int));
myData.Columns.Add(seqCol);
myData.Columns.Add(maxLenCol);
while (reader.Read())
{
var row = myData.NewRow();
bool addRow = false;
int seq;
if (int.TryParse(reader["Seq"].ToString(), out seq))
if (seq > 30)
{
row[seqCol] = seq;
addRow = true;
}
int maxlen;
if (int.TryParse(reader["MaxLen"].ToString(), out maxlen))
if (maxlen > 30.00)
{
row[maxLenCol] = maxlen;
addRow = true;
}
if (addRow)
{
myData.Rows.Add(row);
}
}
Then bind this table to a grid
DataGridView dgv = new DataGridView();
dgv.DataSource = myData;
My Datatable 1 (dtOutput) Format (termid,faultid,faultdesc,faulttime,devicetype)
My Datatable 2 (dtOpenEvent) Format (termid,faultid)
I want to retrieve those values which are present in Datatable 2 but not in Datatable 1...based on two columns (termid,faultid) no table have primary keys.
I Searched on net and find code which return diff between two data table...
Now how can i retrieve column values from it ? either in another data table or in string variable
Code :-
DataTable dtOpenEvent;
dtOpenEvent = Generix.getOpenEvents(ref Connection);
DataTable dtOutput;
dtOutput = Generix.getFeedData(ref Connection);
var matched = from table1 in dtOpenEvent.AsEnumerable()
join table2 in dtOutput.AsEnumerable() on table1.Field<string>("ATM") equals table2.Field<string>("termid")
where table1.Field<int>("Event") == table2.Field<int>("faultid")
select table1;
var missing = from table1 in dtOpenEvent.AsEnumerable()
where !matched.Contains(table1)
select table1;
you can remove all of the columns in dt1 and then do except.
like this:
var diff =dt2.AsEnumerable().Except(dt1.AsEnumerable(), DataRowComparer.Default);
full example:
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt1.Columns.Add("termid", typeof(Int32));
dt1.Columns.Add("faultid", typeof(Int32));
dt1.Columns.Add("faultdesc");
dt2.Columns.Add("termid", typeof(Int32));
dt2.Columns.Add("faultid", typeof(Int32));
dt1.Rows.Add(1,2,"desc");
dt1.Rows.Add(3, 4, "desc");
dt1.Rows.Add(5, 6, "desc");
dt2.Rows.Add(1, 2);
dt2.Rows.Add(3, 4);
dt2.Rows.Add(7, 8);
dt1.Columns.Remove("faultdesc");
var diff =dt2.AsEnumerable().Except(dt1.AsEnumerable(), DataRowComparer.Default);
foreach (var row in diff)
{
Console.WriteLine(row["termid"] + " " + row["faultid"]); //prints 7 8
}
or instead of removing columns you can select them through linq or dataview like this:
var view = new DataView(dt1);
DataTable dt3 = view.ToTable(true, "termid", "faultid");
modified example:
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt1.Columns.Add("termid", typeof(Int32));
dt1.Columns.Add("faultid", typeof(Int32));
dt1.Columns.Add("faultdesc");
dt2.Columns.Add("termid", typeof(Int32));
dt2.Columns.Add("faultid", typeof(Int32));
dt1.Rows.Add(1,2,"desc");
dt1.Rows.Add(3, 4, "desc");
dt1.Rows.Add(5, 6, "desc");
dt2.Rows.Add(1, 2);
dt2.Rows.Add(3, 4);
dt2.Rows.Add(7, 8);
var view = new DataView(dt1);
DataTable dt3 = view.ToTable(true, "termid", "faultid");
var diff =dt2.AsEnumerable().Except(dt3.AsEnumerable(), DataRowComparer.Default);
foreach (var row in diff)
{
Console.WriteLine(row["termid"] + " " + row["faultid"]);
}
As you said : I want to retrieve those values which are present in Datatable 2
but not in Datatable 1...based on two columns `(termid,faultid)`
Translation according to the context of question : You have two tables dtOutput and dtOpenEvent. You want to get values of dtOutput in a third table such that no row of third table has same value with first two cells of any row of dtOpenEvent. Then here it is
DataTable dt3 = new DataTable();
dt3.Columns.Add("termid");
dt3.Columns.Add("faultid");
int nr = 0;
for (int i = 0; i < dtOutput.Rows.Count; i++)
{
bool found = false;
for (int j = 0; j < dtOpenEvent.Rows.Count; j++)
{
if (dtOutput.Rows[i][0] == dtOpenEvent.Rows[j][0]
&& dtOutput.Rows[i][1] == dtOpenEvent.Rows[j][1])
{
found = true;
break;
}
}
if (!found)
{
dt3.Rows.Add(dt3.NewRow());
dt3.Rows[nr][0] = dtOutput.Rows[i][0];
dt3.Rows[nr][1] = dtOutput.Rows[i][1];
nr++;
}
}