I have a datatable and would like to know if its possible for me to select certain columns and input the data on a table. the columns are set out as below
|col1 |col2 |col3|col4 |col5 |col6|col7 |col8 |col9 |col10 |col11 |
I want to select column col1, col2 col6, col7,col3. and dispay the data in a gridview of the rows within the datatable.. currently the code that i am using is below and onmly selects certain data. I am not selecting the data from sql its data being selected from another excel which is stored in a datatable.. but i am in need of the other columns in another area as well.. this data is being written into a table in word
for (int i = 1; i < table.Rows.Count; i++)
{
for (int j = 0; j < table.Columns.Count; j++)
{
if (j == 0)
{
val = filteredData.Rows[row][col].ToString();
}
else
{
val = filteredData.Rows[row][col].ToString();
if (val == "-" || val == "")
{
val = filteredData.Rows[row][col].ToString();
}
else
{
val = Convert.ToString(Math.Round(Convert.ToDouble(filteredData.Rows[row][col]), MidpointRounding.AwayFromZero));
}
}
table[j, i].TextFrame.Text = val;
col++;
}
Also we can try like this,
string[] selectedColumns = new[] { "Column1","Column2"};
DataTable dt= new DataView(fromDataTable).ToTable(false, selectedColumns);
First store the table in a view, then select columns from that view into a new table.
// Create a table with abitrary columns for use with the example
System.Data.DataTable table = new System.Data.DataTable();
for (int i = 1; i <= 11; i++)
table.Columns.Add("col" + i.ToString());
// Load the table with contrived data
for (int i = 0; i < 100; i++)
{
System.Data.DataRow row = table.NewRow();
for (int j = 0; j < 11; j++)
row[j] = i.ToString() + ", " + j.ToString();
table.Rows.Add(row);
}
// Create the DataView of the DataTable
System.Data.DataView view = new System.Data.DataView(table);
// Create a new DataTable from the DataView with just the columns desired - and in the order desired
System.Data.DataTable selected = view.ToTable("Selected", false, "col1", "col2", "col6", "col7", "col3");
Used the sample data to test this method I found:
Create ADO.NET DataView showing only selected Columns
The question I would ask is, why are you including the extra columns in your DataTable if they aren't required?
Maybe you should modify your SQL select statement so that it is looking at the specific criteria you are looking for as you are populating your DataTable.
You could also use LINQ to query your DataTable as Enumerable and create a List Object that represents only certain columns.
Other than that, hide the DataGridView Columns that you don't require.
Here's working example with anonymous output record, if you have any questions place a comment below:
public partial class Form1 : Form
{
DataTable table;
public Form1()
{
InitializeComponent();
#region TestData
table = new DataTable();
table.Clear();
for (int i = 1; i < 12; ++i)
table.Columns.Add("Col" + i);
for (int rowIndex = 0; rowIndex < 5; ++rowIndex)
{
DataRow row = table.NewRow();
for (int i = 0; i < table.Columns.Count; ++i)
row[i] = String.Format("row:{0},col:{1}", rowIndex, i);
table.Rows.Add(row);
}
#endregion
bind();
}
public void bind()
{
var filtered = from t in table.AsEnumerable()
select new
{
col1 = t.Field<string>(0),//column of index 0 = "Col1"
col2 = t.Field<string>(1),//column of index 1 = "Col2"
col3 = t.Field<string>(5),//column of index 5 = "Col6"
col4 = t.Field<string>(6),//column of index 6 = "Col7"
col5 = t.Field<string>(4),//column of index 4 = "Col3"
};
filteredData.AutoGenerateColumns = true;
filteredData.DataSource = filtered.ToList();
}
}
You can create a method that looks like this:
public static DataTable SelectedColumns(DataTable RecordDT_, string col1, string col2)
{
DataTable TempTable = RecordDT_;
System.Data.DataView view = new System.Data.DataView(TempTable);
System.Data.DataTable selected = view.ToTable("Selected", false, col1, col2);
return selected;
}
You can return as many columns as possible.. just add the columns as call parameters as shown below:
public DataTable SelectedColumns(DataTable RecordDT_, string col1, string col2,string col3,...)
and also add the parameters to this line:
System.Data.DataTable selected = view.ToTable("Selected", false,col1, col2,col3,...);
Then simply implement the function as:
DataTable myselectedColumnTable=SelectedColumns(OriginalTable,"Col1","Col2",...);
Thanks...
DataView dv = new DataView(Your DataTable);
DataTable dt = dv.ToTable(true, "Your Specific Column Name");
The dt contains only selected column values.
Related
I tried this solution below:
This Row already belongs to another table error when trying to add rows?
I have a Datatable that contains 597 Columns and 20 Rows and are trying to export the data to excel. However, Excel has a maximum column count 256 and so I need to divide the source data into 3 datatables to make the export work.
Below is the code I have written.
var dtmasterdata = data.Tables[name];
for (int j = 1; j < datatableNumberCount; j++)
{
DataTable dt2 = new DataTable();
dt2.TableName = "Master_" + j;
dt2 = dtmasterdata.Copy();
foreach (DataColumn col in dtmasterdata.Columns)
{
DataColumn dtcol = new DataColumn();
dtcol = col;
dt2.Columns.Add(dtcol.ColumnName, dtcol.DataType);
}
for (int k = 0; k < dtmasterdata.Rows.Count; k++)
{
DataRow dr = dt2.NewRow();
dr = dtmasterdata.Rows[k];
dt2.ImportRow(dtmasterdata.Rows[k]);
//dt2.Rows.Add(dr.ItemArray);
}
After that I need to delete few columns like below and I want to create 3 datatables
foreach (DataColumn col in dtmasterdata.Columns)
{
if (j == 1)
{
// condition 1
if (col.Ordinal >= 255)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 2)
{
// condition 2.
if (col.Ordinal < 255 || col.Ordinal >= 510)
{
dt2.Columns.RemoveAt(col.Ordinal);
}
}
if (j == 3)
{
// condition 3.
if (col.Ordinal <= 510 || col.Ordinal >= 765)
{
dt2.Columns.Add(col);
}
}
}
int worksheetNumber = 1;
string worksheetNameWithNumber = "Master Data";
if (worksheetNumber > 1)
worksheetNameWithNumber = String.Format("{0}_{1}", ws1, worksheetNumber.ToString());
Infragistics.Excel.Worksheet worksheet = wb.Worksheets.Add(worksheetNameWithNumber);
Infragistics.WebUI.UltraWebGrid.UltraWebGrid masterData1 = new Infragistics.WebUI.UltraWebGrid.UltraWebGrid("masterDataGrid");
masterData1.Browser = Infragistics.WebUI.UltraWebGrid.BrowserLevel.UpLevel;
masterData1.DataSource = dt2;
masterData1.DataMember = "Master_" + j;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Bold = true;
masterData1.DisplayLayout.HeaderStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.HeaderStyleDefault.Font.Size = FontUnit.Parse("10px");
masterData1.DisplayLayout.HeaderStyleDefault.BackColor = System.Drawing.Color.LightGray;
masterData1.DisplayLayout.RowStyleDefault.Font.Name = "Arial";
masterData1.DisplayLayout.RowStyleDefault.Font.Size = FontUnit.Parse("10px");
Infragistics.WebUI.UltraWebGrid.UltraGridBand masterBand1 = new Infragistics.WebUI.UltraWebGrid.UltraGridBand();
masterData1.Bands.Add(masterBand1);
dgResults.Controls.Add(masterData1);
masterData1.DataBind();
wb.ActiveWorksheet = worksheet;
this.ugWebGridExporter.Export(masterData1, worksheet);
worksheetNumber++;
Your error is because you are trying to add a column to a datatable that already belongs to your source datatable.
dt2.Columns.Add(col);
You can't just iterate through the columns of a datatable and add them to another.
I've a solution to this, which involves cloning the source data and removing what you don't need.
1st, make 3 clones of the datatables you need. Below is an example with me creating my own source table with 596 columns. Notice that clone only takes the data table structure, no data!
var source597ColsTable = new DataTable("Source");
for (var i = 0; i <= 596; i++)
{
source597ColsTable.Columns.Add(new DataColumn("Column" + i , typeof(string)));
}
DataRow newRow = source597ColsTable.NewRow();
source597ColsTable.Rows.Add(newRow);
var cols0To199Table = source597ColsTable.Clone();
var cols200To399Table = source597ColsTable.Clone();
var cols400To596Table = source597ColsTable.Clone();
Next copy all the rows from the source table into the clones. The below is a simple function to do so.
private DataTable CopyRowsFromSource(DataTable sourceTable, DataTable destinationTable)
{
foreach (DataRow row in sourceTable.Rows)
{
destinationTable.Rows.Add(row.ItemArray);
}
return destinationTable;
}
Then call this function for each of your tables.
cols0To199Table = CopyRowsFromSource(source597ColsTable, cols0To199Table);
cols200To399Table = CopyRowsFromSource(source597ColsTable, cols200To399Table);
cols400To596Table = CopyRowsFromSource(source597ColsTable, cols400To596Table);
Finally, remove all the columns from the datatables to give you your split.
private DataTable RemoveColumns(DataTable table, int startCol, int endCol)
{
var colsToRemove = new List<DataColumn>();
for (var colCount = startCol; colCount <= endCol; colCount++)
{
colsToRemove.Add(table.Columns[colCount]);
}
foreach (DataColumn col in colsToRemove)
{
table.Columns.Remove(col);
}
return table;
}
Then call.. again for each cloned table.
cols0To199Table = RemoveColumns(cols0To199Table, 200, 596);
cols200To399Table = RemoveColumns(cols200To399Table, 0, 199);
cols200To399Table = RemoveColumns(cols200To399Table, 200, 396);
cols400To596Table = RemoveColumns(cols400To596Table, 0, 399);
After running this, you will have 3 datatables, columns 0-199, 200-399 and 400-596.
Hope that helps.
I am not sure to have really understood all of your code, but to copy a subset of columns to another datatable there is a very simple method in the DataView class named ToTable where you can list the columns you want in the new table. As added bonus, this method copies also the data in the 20 rows of your original table.
So the only difficult is to list these columns to the method.
You can proceed in this way using linq over the DataColumn collection
string[] firstCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] secondCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(255)
.Take(255)
.Select(x => x.ColumnName).ToArray();
string[] thirdCols = dtmasterdata.Columns
.Cast<DataColumn>()
.Skip(510)
.Select(x => x.ColumnName).ToArray();
DataTable t1 = dtmasterdata.DefaultView.ToTable("Master_1", false, firstCols);
DataTable t2 = dtmasterdata.DefaultView.ToTable("Master_2", false, secondCols);
DataTable t3 = dtmasterdata.DefaultView.ToTable("Master_3", false, thirdCols);
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 working on a project that reads in a hardware configuration xml file and parses and sorts its data by protocol type and channels for further modification that is displayed in a two column gridview. Column 1 holds the channel names as a DataGridViewTextBoxColumn while column 2 is setup as a DataGridViewComboBoxColumn where the user should be able to select an item from the dropdown list that was generated from a query from a SQL database (Channel-Type).
The SQL database table itself has couple columns that are as follows:
Interface Channel-Type
The "Interface" column is used as a key to distinguish the "Channel-Type" if they are RS232, RS422, RS485, and so on.
As I populate the DataGridView, I sort it out to first run through all RS422 channel listing, followed by RS232 listings and so on. However, to do this I would need to be able to change the DataSource for the ComboBoxColumn to have different queries such as for the first it would be
"SELECT Channel_Type FROM Table1 WHERE Interface='RS422'"
while for the second one I would need to run
"SELECT Channel_Type FROM Table1 WHERE Interface='RS232'"
So in the code I have the following:
private void scanner()
{
//...code for parser that assembles a List<> ...
ChannelTypeColumn.DataSource = Populate("SELECT Channel_Type FROM Table1 WHERE Interface='RS422'");
ChannelTypeColumn.ValueMember = "Channel_Type";
ChannelTypeColumn.DisplayMember = ChannelTypeColumn.ValueMember;
for(int x = 0; x < ChannelRS422List.Count; x++)
{
RowDataBuffer[0] = ChannelRS422List.channel;
dgv.Rows.Add(RowDataBuffer);
}
ChannelTypeColumn.DataSource = Populate("SELECT Channel_Type FROM Table1 WHERE Interface='RS232'");
for(int x = 0; x < ChannelRS232List.Count; x++)
{
RowDataBuffer[0] = ChannelRS232List.channel;
dgv.Rows.Add(RowDataBuffer);
}
}
private DataTable Populate(string query)
{
SqlCommand command = new SqlCommand(query, connection);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = command;
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
adapter.Fill(table);
return table;
}
Unfortunately I am not sure how to change datasources correctly, since doing it with this methods only would show me a list of the items in the last datasource definition.
Any help and advise would be greatly appreciated!
Thanks!
After much trying, I finally found a method to do the problem. Instead of doing this by the column, I need to do it by the cell for the row I need it at.
private void scanner()
{
//...code for parser that assembles a List<> ...
for(int x = 0; x < ChannelRS422List.Count; x++)
{
RowDataBuffer[0] = ChannelRS422List.channel;
dgv.Rows.Add(RowDataBuffer);
}
int rowCount = 0;
for (int row = 0; row < dgv.Rows.Count; row++)
{
DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)(dgv.Rows[row].Cells[1]);
cell.DataSource = Populate("SELECT Channel_Type FROM Table1 WHERE Interface='RS422'");
cell.ValueMember = "Channel_Type";
cell.DisplayMember = cell.ValueMember;
rowCount = row+1;
}
for(int x = 0; x < ChannelRS232List.Count; x++)
{
RowDataBuffer[0] = ChannelRS232List.channel;
dgv.Rows.Add(RowDataBuffer);
}
for (int row = rowCount; row < dgv.Rows.Count; row++)
{
DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)(dgv.Rows[row].Cells[1]);
cell.DataSource = Populate("SELECT Channel_Type FROM Table1 WHERE Interface='RS232'");
cell.ValueMember = "Channel_Type";
cell.DisplayMember = cell.ValueMember;
rowCount = row+1;
}
}
I have 2 datatable let say dtData1 and dtData2. I have records in both the datatable I want to compare both the data table and want to create a new datatable let say dtData3 with uniqe records.
suppose: dtData1 has 10 records, and dtData2 has 50 records, but what ever records are there in dtData2 in that 7 records are same as dtData1. So here I want unique records in dtData3, means I want only 43 records in dtData3.
we don't know in datatable where we have the duplicate, and its possible that we will not have duplicates or its also possible that we will have all duplicate records.
So in dtData3 I need unique records
Some one please help me.
var dtData3 = dtData2.AsEnumerable().Except(dtData1.AsEnumerable(), DataRowComparer.Default);
Use this.. Probably it will help you.
Suppose you have two data table
DataTable dt1 = new DataTable();
dt1.Columns.Add("Name");
dt1.Columns.Add("ADD");
DataRow drow;
for (int i = 0; i < 10; i++)
{
drow = dt1.NewRow();
drow[0] = "NameA" + 1;
drow[1] = "Add" + 1;
dt1.Rows.Add();
}
DataTable dt2 = new DataTable();
dt2.Columns.Add("Name");
dt2.Columns.Add("ADD");
DataRow drow1;
for (int i = 0; i < 11; i++)
{
drow1 = dt2.NewRow();
drow1[0] = "Name" + 1;
drow1[1] = "Add" + 1;
dt2.Rows.Add();
}
Now To solve your problem Call :-
DataTable d3 = CompareTwoDataTable(dt1, dt2);
The method is something like this;--
public static DataTable CompareTwoDataTable(DataTable dt1, DataTable dt2)
{
dt1.Merge(dt2);
DataTable d3 = dt2.GetChanges();
return d3;
}
Then where the need to compare dtData1 and dtData2? Instead you can copy the contents from dtData2 to dtData3 starting from index7.
First Create Array variables to save unique coloumn values for datatable3. Use Foreach loop with second gridview rows. If any match then dnt save it in a array value, if dnt match then save it in arrays. and display it by attaching with third gridview.......
e.g
string[] name = new string[4];
int i=0,j=0;
foreach(GridViewRows gv in GridView1.rows)
{
if(gv.Cells[0].Text == GridView2.Rows[i].Cells[0].Text)' //if match
{
// dnt save
}
else' //if dnt match save in array for further use
{
name[j] = gv.Cells[0].Text;
j= j++;
}
i=i++;
}
After Saving unique values in Array "name"...Bind it in Third Gridview
During DataBound of third Gridview add this method...
Private void GridView3_RowDataBound(object sender,EventArgs e)
{
if(e.Row.RowState == DataControlState.DataRow)
{
foreach(string nm in name)
{
e.Rows.Cells.Add(name);
}
}
}
public DataTable CompareTwoDataTable(DataTable dtOriginalTable, DataTable dtNewTable, ArrayList columnNames)
{
DataTable filterTable = new DataTable();
filterTable = dtNewTable.Copy();
string filterCriterial;
if (columnNames.Count > 0)
{
for (int iNewTableRowCount = 0; iNewTableRowCount < dtNewTable.Rows.Count; iNewTableRowCount++)
{
filterCriterial = string.Empty;
foreach (string colName in columnNames.ToArray())
{
filterCriterial += colName.ToString() + "='" + dtNewTable.Rows[iNewTableRowCount][colName].ToString() + "' AND ";
}
filterCriterial = filterCriterial.TrimEnd((" AND ").ToCharArray());
DataRow[] dr = dtOriginalTable.Select(filterCriterial);
if (dr.Length > 0)
{
filterTable.Rows[filterTable.Rows.IndexOf(filterTable.Select(filterCriterial)[0])].Delete();
}
}
}
return filterTable;
}
I have an existing DataTable with thousand rows and want to find the rows and set it to become top rows.
I don't know if you're able to, but I would probably add a dummy column to sort by, give the rows you want a higher value in the dummy column, and then sort by the column from bigger to smaller with a DataView.
private void ModifyTable(DataTable toModify)
{ //Add a column to sort by later.
DataColumn col = toModify.Columns.Add("DummySort", typeof(int));
col.DefaultValue = 0;
}
private void SetDummyColumnValue(DataRow dr, int value)
{ //Mark the columns you want to sort to bring to the top.
//Give values bigger than 0!
dr["DummySort"] = value;
}
private DataTable GetSortedTable(DataTable modifiedTable)
{
//Sort by the column from bigger to smaller
DataView dv = new DataView(modifiedTable);
dv.Sort = "DummySort DESC"; return dv.ToTable();
}
You can try to remove and insert row
public void MoveDataRowTo(DataRow dataRow,int destination)
{
DataTable parentTable = dataRow.Table;
int rowIndex = parentTable.Rows.IndexOf(dataRow);
if (rowIndex > 0)
{
DataRow newDataRow = parentTable.NewRow();
for (int index = 0; index < dataRow.ItemArray.Length; index++)
newDataRow[index] = dataRow[index];
parentTable.Rows.Remove(dataRow);
parentTable.Rows.InsertAt(newDataRow, destination);
dataRow = newDataRow;
}
}
DataSet dsAct = new DataSet();
OleDbDataAdapter odaTem = new OleDbDataAdapter("SELECT ActivityId, Activity FROM tbl_Activity", ocnConn);
odaTem.Fill(dsAct, "Activity");
DataRow drTem;
int i = 0;
//Rows want set to be on top is in the table "TopActivity"
foreach (DataRow dr in dsAct.Tables["TopActivity"].Rows)
{
drTem = dsAct.Tables["Activity"].NewRow();
//Clone the row
drTem.ItemArray = dsAct.Tables["Activity"].Rows.Find(dr["Activity_ID"]).ItemArray;
dsAct.Tables["Activity"].Rows.RemoveAt( dsAct.Tables["Activity"].Rows.IndexOf( dsAct.Tables["Activity"].Rows.Find(dr["Activity_ID"])));
dsAct.Tables["Activity"].Rows.InsertAt(drTem, i);
i++;
}