I have two datatables
dtTable1:
Name Id Contact
Gems A1 8888880000
George A2 0000008888
dtTable2:
Col1 Col2 Col3
XXX1 YYY1 ZZZ1
XXX2 YYY2 ZZZ2
XXX3 YYY3 ZZZ3
XXX4 YYY4 ZZZ4
My required DataTable is:
Name Id Contact Col1 Col2 Col3
Gems A1 8888880000 XXX1 YYY1 ZZZ1
George A2 0000008888 XXX2 YYY2 ZZZ2
null null null XXX3 YYY3 ZZZ3
null null null XXX4 YYY4 ZZZ4
How can I do it with C#
Here you go. Might not be pretty but does the job.
No matter which DataTable has more row it will add them.
private static DataTable MergeTables(DataTable dt1, DataTable dt2)
{
DataTable merged = new DataTable();
//copy column struct from dt1
merged = dt1.Clone();
//create columns from dt2
foreach (DataColumn col in dt2.Columns)
{
merged.Columns.Add(col.ColumnName);
}
int rows;
if (dt1.Rows.Count > dt2.Rows.Count)
{
rows = dt1.Rows.Count;
}
else
{
rows = dt2.Rows.Count;
}
for (int i = 0; i < rows; i++)
{
DataRow row = merged.NewRow();
if ( i < dt1.Rows.Count)
{
for (int c = 0; c < dt1.Columns.Count; c++)
{
row[c] = dt1.Rows[i][c];
}
}
if (i < dt2.Rows.Count)
{
for (int c2 = dt1.Columns.Count; c2 < dt2.Columns.Count + dt1.Columns.Count; c2++)
{
row[c2] = dt2.Rows[i][c2-dt1.Columns.Count];
}
}
merged.Rows.Add(row);
}
return merged;
}
DataTable mergeDataTables(DataTable dt1, DataTable dt2)
{
if(dt1.Rows.Count != dt2.Rows.Count ) throw new Exception();
var dtResult = new DataTable();
//add new columns
foreach (DataColumn col in dt1.Columns)
dtResult.Columns.Add(col.ColumnName, col.DataType);
foreach (DataColumn col in dt2.Columns)
dtResult.Columns.Add(col.ColumnName, col.DataType);
//fill data
for (int i = 0; i < dt1.Rows.Count; i++)
{
dtResult.Rows.Add(dt1.Rows[i].ItemArray.Concat(dt2.Rows[i].ItemArray).ToArray());
}
return dtResult;
}
I have changed solution of lomed.
May be this not perfect solution. But it works for the similar scenario as required in the question:
DataTable MergeDataTables(DataTable dt1, DataTable dt2)
{
var dtResult = new DataTable();
foreach (DataColumn col in dt1.Columns)
dtResult.Columns.Add(col.ColumnName, col.DataType);
foreach (DataColumn col in dt2.Columns)
dtResult.Columns.Add(col.ColumnName, col.DataType);
//cond: to check which if datatable1 is bigger
if (dt1.Rows.Count > dt2.Rows.Count)
{
for (int i = 0; i < dt1.Rows.Count; i++)
{
if (i < dt2.Rows.Count)
dtResult.Rows.Add(dt1.Rows[i].ItemArray.Concat(dt2.Rows[i].ItemArray).ToArray());
else
{
DataRow dr = dtResult.NewRow();
foreach (DataColumn col in dt1.Columns)
dr[col.ColumnName] = dt1.Rows[i][col.ColumnName];
dtResult.Rows.Add(dr);
}
}
}
//if rows equal or datatable2 is bigger
else
{
for (int i = 0; i < dt2.Rows.Count; i++)
{
if (i < dt1.Rows.Count)
dtResult.Rows.Add(dt1.Rows[i].ItemArray.Concat(dt2.Rows[i].ItemArray).ToArray());
else
{
DataRow dr = dtResult.NewRow();
foreach (DataColumn col in dt2.Columns)
dr[col.ColumnName] = dt2.Rows[i][col.ColumnName];
dtResult.Rows.Add(dr);
}
}
}
return dtResult;
}
Related
I tried to add values to DataTable columns by vertically in loops.
But output doesn't looks good as expected.
DataTables dynamictable = new DataTable()
foreach (DataColumn cl in dataTable.Columns)
{
dynamictable.Columns.Add(cl.ToString());
List<string> plainList = dataTable.AsEnumerable().Select(x => x[cl].ToString()).ToList();
for (int i=0; i< plainList.Count(); i++)
{
DataRow row = dynamictable.NewRow();
row[cl.ToString()] = plainList[i];
enryptedTable.Rows.Add(row);
}
}
Actual Output got from my code:
Expected Output:
change your code to :
DataTable dynamictable = new DataTable();
int col = 0;
foreach (DataColumn cl in dataTable.Columns)
{
dynamictable.Columns.Add(cl.ToString());
List<string> plainList = dataTable.AsEnumerable().Select(x => x[cl].ToString()).ToList();
DataRow row = null;
for (int i = 0; i < plainList.Count(); i++)
{
row = dynamictable.NewRow();
row[col] = plainList[i];
dynamictable.Rows.Add(row);
}
col++;
}
//now set dynamictable to datagridview or .....
How can I query an Excel file where the rows and columns are reversed / rotated 90 degrees?
Can it be done with a SELECT query, or do I need to recurse the cells programmatically?
It's for a .NET app, so linq or other suggestions are welcome.
Transpose a Datatable with a code like this:
private DataTable GenerateTransposedTable(DataTable inputTable)
{
DataTable outputTable = new DataTable(inputTable.TableName);
outputTable.Columns.Add(inputTable.Columns[0].ColumnName);
foreach (DataRow inRow in inputTable.Rows)
{
string newColName = inRow[0].ToString();
outputTable.Columns.Add(newColName);
}
for (int rCount = 1; rCount <= inputTable.Columns.Count - 1; rCount++)
{
DataRow newRow = outputTable.NewRow();
newRow[0] = inputTable.Columns[rCount].ColumnName;
for (int cCount = 0; cCount <= inputTable.Rows.Count - 1; cCount++)
{
string colValue = inputTable.Rows[cCount][rCount].ToString();
newRow[cCount + 1] = colValue;
}
outputTable.Rows.Add(newRow);
}
return outputTable;
}
.NET does not include a method to transpose data tables. You have to make your own. This website Link has a tutorial on an example transpose method. I will copy and paste the code snippet below:
private DataTable Transpose(DataTable dt)
{
DataTable dtNew = new DataTable();
//adding columns
for(int i=0; i<=dt.Rows.Count; i++)
{
dtNew.Columns.Add(i.ToString());
}
//Changing Column Captions:
dtNew.Columns[0].ColumnName = " ";
for(int i=0; i<dt.Rows.Count; i++)
{
//For dateTime columns use like below
dtNew.Columns[i+1].ColumnName =Convert.ToDateTime(dt.Rows[i].ItemArray[0].ToString()).ToString("MM/dd/yyyy");
//Else just assign the ItermArry[0] to the columnName prooperty
}
//Adding Row Data
for(int k=1; k<dt.Columns.Count; k++)
{
DataRow r = dtNew.NewRow();
r[0] = dt.Columns[k].ToString();
for(int j=1; j<=dt.Rows.Count; j++)
r[j] = dt.Rows[j-1][k];
dtNew.Rows.Add(r);
}
return dtNew;
}
I have a function which reads all the tab delimited records from a text file into a datatble, but I have a lot empty or null columns also which are tab delimited. I just want to read all records where column 3 is not null or non empty. how can I do it?
Here is my simple method
public DataTable ConvertTextToDataTable(string filePath, int numberOfColumns)
{
DataTable tbl = new DataTable();
for (int col = 0; col < numberOfColumns; col++)
tbl.Columns.Add(new DataColumn("Column" + (col + 1).ToString()));
string[] lines = System.IO.File.ReadAllLines(filePath);
int i = 0;
foreach (string line in lines)
{
var cols = line.Split('\t');
DataRow dr = tbl.NewRow();
for (int cIndex = 0; cIndex < numberOfColumns; cIndex++)
{
dr[cIndex] = cols[cIndex];
}
tbl.Rows.Add(dr);
i++;
}
return tbl;
}
The simplest would be to insert a check for IsNullOrWhiteSpace for column 3 before creating and and adding values to the datatable like:
public DataTable ConvertTextToDataTable(string filePath, int numberOfColumns)
{
DataTable tbl = new DataTable();
for (int col = 0; col < numberOfColumns; col++)
tbl.Columns.Add(new DataColumn("Column" + (col + 1).ToString()));
var lines = System.IO.File.ReadLines(filePath);
int i = 0;
foreach (string line in lines)
{
var cols = line.Split('\t');
if (cols.Length > 3 && String.IsNullOrWhiteSpace(cols[3]))
{
continue; //Ignore this line
}
DataRow dr = tbl.NewRow();
for (int cIndex = 0; cIndex < numberOfColumns; cIndex++)
{
dr[cIndex] = cols[cIndex];
}
tbl.Rows.Add(dr);
i++;
}
return tbl;
}
Also notice the use of var lines = System.IO.File.ReadLines(filePath); instead of File.ReadAllLines, since it will evaluate the file line by line, instead of loading up all the files content in memory.
I have two datatables, each with 1 column:
dtTempCM
dtOldTempCM
In both tables, the only column name is Column1
I also have 2 datagridviews in the form that are each bound to a datatable:
dgvCurrentCM.DataSource = dtTempCM;
dgvOldCM.DataSource = dtOldTempCM;
How can I compare each row, and highlight it in one (or both) of the datagridviews if they don't match? So far, I have this:
foreach (DataRow row1 in dtTempCM.Rows)
{
foreach (DataRow row2 in dtOldTempCM.Rows)
{
var array1 = row1.ItemArray;
var array2 = row2.ItemArray;
if (array1.SequenceEqual(array2))
{
//change row/cell color in dgvCurrentCM to red
//change row/cell color in dgvOldCM to red
}
}
}
Any ideas? Thank you!
EDIT: I tried this too, but it changes the color of every cell since it compares every row in dgvOldCM to a single row in dgvCurrentCM:
foreach (DataGridViewRow row1 in dgvCurrentCM.Rows)
{
foreach (DataGridViewRow row2 in dgvOldCM.Rows)
{
if (row1.Cells[0].Value != row2.Cells[0].Value)
{
row1.DefaultCellStyle.ForeColor = Color.Red;
row2.DefaultCellStyle.ForeColor = Color.Red;
}
}
}
I would iterate on one of the gridview, comparing to the other like this:
for (int i = 0; i < dgvCurrentCM.RowCount; i++)
{
if (dgvCurrentCM.Rows[i].Cells[0].Value != null)
{
if ((int)dgvCurrentCM.Rows[i].Cells[0].Value != (int)dgvOldCM.Rows[i].Cells[0].Value)
{
dgvCurrentCM.Rows[i].DefaultCellStyle.ForeColor = Color.Red;
dgvOldCM.Rows[i].DefaultCellStyle.ForeColor = Color.Red;
}
}
}
You can generate a Intersection of two Datatables, and then mark the rows:
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
dt1.Columns.Add("Col");
dt2.Columns.Add("Col");
for (int i = 0; i < 10; i++)
{
DataRow dr = dt1.NewRow();
dr["Col"] = i.ToString();
dt1.Rows.Add(dr);
}
for (int i = 5; i < 15; i++)
{
DataRow dr = dt2.NewRow();
dr["Col"] = i.ToString();
dt2.Rows.Add(dr);
}
var result = dt1.AsEnumerable().Intersect(dt2.AsEnumerable(), DataRowComparer.Default);
dataGridView1.DataSource = dt1;
dataGridView2.DataSource = dt2;
for (int i = 0; i < dataGridView1.RowCount -1; i++)
{
DataRow currRow = ((DataRowView)dataGridView1.Rows[i].DataBoundItem).Row;
if (result.Contains(currRow))
dataGridView1.Rows[i].DefaultCellStyle.ForeColor = Color.Red;
}
if (array1.SequenceEqual(array2))
{
}
else
{
//Do your action here!
}
Is it possible to convert a sqlceresultset.resultview to datatable?
Not tested, but this should do what you need:
public DataTable ResultSetToDataTable(SqlCeResultSet set)
{
DataTable dt = new DataTable();
// copy columns
for (int col = 0; col < set.FieldCount; col++)
{
dt.Columns.Add(set.GetName(col), set.GetFieldType(col));
}
// copy data
while (set.Read())
{
DataRow row = dt.NewRow();
for (int col = 0; col < set.FieldCount; col++)
{
int ordinal = set.GetOrdinal(GetName(col));
row[col] = set.GetValue(ordinal);
}
dt.Rows.Add(row);
}
return dt;
}
There's no built-in way to do this (that I know of), probably because a SqlCeResultSet does not store actual data like a DataTable does.