Merge two DataTables without duplicate values for a column - c#

I have two DataTables like
DataTable1(With default values)-
Tag |Alias|Value |Type
abc |"" |default|default
xyz |"" |default|default
DataTable2(With actual values)-
Tag |Alias |Value |Type
abc |test |12 |Real
Now if I use DataTable.Merge() I get the rows with both default and actual values for tag abc.
I need only the actual values for a particular tag present in 2nd table, if not the default values from 1st table.
How do i do this?

Just add a primary key constraint to the Tag column before merging.
Example:
var dt1 = new DataTable();
var prime1 = dt1.Columns.Add("Tag", typeof(string));
dt1.Columns.Add("Value", typeof(string));
dt1.Rows.Add(new object[]{"abc", "default"});
dt1.Rows.Add(new object[]{"xyz", "default"});
dt1.PrimaryKey = new DataColumn[]{ prime1 };
var dt2 = new DataTable();
var prime2 = dt2.Columns.Add("Tag", typeof(string));
dt2.Columns.Add("Value", typeof(string));
dt2.Rows.Add(new object[]{"abc", "12"});
dt2.PrimaryKey = new DataColumn[]{ prime2 };
dt1.Merge(dt2);
dt1 now looks like:

Related

DataTable expression refering to other DataTable column

I have 2 DataTables, DT1 and DT2.
DT1 has columns A1, B1 and DT2 has columns A2, B2.
I'd like to add an expression to A1like A1 = A2 + B2
Is this possible to do without joining or merging the 2 DataTables, this is similar to the way spreadsheets operate?.
Is there any other way to do this, any other data structures or techniques apart from DataTable that would get this done?.
I see that a DataTable won't be able the deduce from a string the tables that the columns belong to?
Is it possible that we can add these 2 DataTables to a DataSet and then do the expression referring to tables present in the DataSet.
Edit:
I have used addition as an example however the expressions can have multiple combinations of math and logic operators and sometimes basic math functions.
See code below
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(string));
dt1.Columns.Add("A1", typeof(int));
dt1.Columns.Add("B1", typeof(int));
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(string));
dt2.Columns.Add("A2", typeof(int));
dt2.Columns.Add("B2", typeof(int));
DataSet ds = new DataSet()
ds.Tables.Add(dt1);
ds.Tables.Add(dt2);
foreach(DataRow row in dt1.AsEnumerable())
{
DataRow match = dt2.AsEnumerable().Where(x => x.Field<string>("ID") == row.Field<string>("ID")).First();
row["A1"] = match.Field<int>("A2") + match.Field<int>("B2");
}

How to add column to datatable from another datatable

I have two data tables dt1 and dt2, both share a common column. How to map the common column and add a new column with data to data table dt1.
DataTable dt1=new DataTable();
DataTable dt2=new DataTable();
sqlDataAdapter da1=new sqlDataAdapter("select col1,col2,col3,col4 from table",connection);
dataset ds1=new dataset();
da1.fill(ds);
dt1=ds.tables[0];
similarly for dt2 the select statement is "select col1,somecol from sometable" rest is the same as dt1.
for dt1 the output is: and the output for dt2
col1 col2 col3 col4 col1 somecol
1 2 3 4 1 true
2 5 6 ... 2 false..
i tried like below:
datatable dtTotal=new datatable();
dtTotal=dt1.clone();
foreach(datacolumn col in dt2.columns)
{
if(col.columnname=="somecol")
{
dtTotal.columns.add("somecol");
dtTotal.columns["somecol"].Datatype=col.Datatype;
}
}
foreach(datarow dr in dt1.rows)
{
dtTotal.importrows(dr);
}
//here a column is added but i don't understand how to import data into that column
I want to have a outpu like below:
col1 col2 col3 col4 somecol
1 2 3 4 true
2 5 6 7 false...
I cannot write a simple join while selecting the the data itself, because the dt2 data is coming from more complex calculations. so I have to do it at datatable level only.
if number of rows in dt1 doesnt match with number of rows in dt2 then dt2 should be added new rows with default value false.
You can use the DataTable.Merge method. The command dt1.Merge(dt2) adds to dt1 the additional columns and the additional data records from dt2. The data from dt2 will overwrite the data from dt1 that share the same primary key value and the same column name.
DataTable dt1 = new DataTable();
DataTable dt2 = new DataTable();
// Fill the data tables
...
// Set the default value for boolean column
dt2.Columns[4].DefaultValue = false;
// Set the primary keys
dt1.PrimaryKey = new DataColumn[] { dt1.Columns[0] }; // Use the appropriate column index
dt2.PrimaryKey = new DataColumn[] { dt2.Columns[0] }; // Use the appropriate column index
// Merge the two data tables in dt1
dt1.Merge(dt2);

How to split string by "#" and store result in a DataTable

I have this string:
1#3.doc#0.036/n
2#1.doc#0.026/n
I want to split it on # and put every line in a single row inside DataTable
like this:
1 3.doc 0.036
2 1.doc 0.026
I have a DataTable like this:
DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("FileName", typeof(string));
table.Columns.Add("Content", typeof(string));
How can I do that?
Here is how you would split a string into lines, and then those lines into different parts.
Your string is first split by the new line character \n into an array of lines string[].
Then those lines, one by one, are split into parts by Split('#').
And finally those parts are added to your table with the columns you created.
Remember to save the columns you created and don't forget to add the newly created row to the table.
DataTable table = new DataTable();
DataColumn colID = table.Columns.Add("Id", typeof(int));
DataColumn colFileName = table.Columns.Add("FileName", typeof(string));
DataColumn colContent = table.Columns.Add("Content", typeof(string));
string source = "1#3.doc#0.036\n2#1.doc#0.026\n";
string[] lines = source.Split('\n');
foreach(var line in lines)
{
string[] split = line.Split('#');
DataRow row = table.NewRow();
row.SetField(colID, int.Parse(split[0]));
row.SetField(colFileName, split[1]);
row.SetField(colContent, split[2]);
table.Rows.Add(row);
}
Adding data to the row with row["FileName"] = data is also possible, but this will break if you change the name of your column, while references to the column objects are checked by the compiler and your IDE. Also this article explains how to create a typed DataTable, which is something you may want to do.
erm,
var stuff = someString.Split('\n')
.Select(r => r.Split('#')
.Select(a => new
{
Id = int.Parse(a[0]),
FileName = a[1],
Content = a[2]
})
.ToList();
This will give you an IList of an anonymous type. Its not worth putting it in a DataTable.

How to disable MS chart series grouping in C#?

My chart series are really near by each other and this is a problem. I don't know why they are grouped, they look like : http://i39.tinypic.com/wks007.png or http://blogs.msdn.com/blogfiles/alexgor/WindowsLiveWriter/DataBindingMSChartcontrol_10712/image_2.png, but must be separate :(
I want to have each bar with his own name without grouping.
Like on second image, Andrew has 5 Columns near by each other with one title: "Andrew", but I want to have them separately)
How I can do this?
I use the MS chart library
P.S. excuse me for my english :)
My code example:
var table = new DataTable();
s = chart1.Series.Add("Ser1");
s.XValueMember = "Col1";
s.YValueMembers = "Col1_Count";
s = chart1.Series.Add("Ser2");
s.XValueMember = "Col2";
s.YValueMembers = "Col2_Count";
s = chart1.Series.Add("Ser3");
s.XValueMember = "Col3";
s.YValueMembers = "Col3_Count";
table.Columns.Add("Col1", typeof(string));
table.Columns.Add("Col1_Count", typeof(int));
table.Columns.Add("Col2", typeof(string));
table.Columns.Add("Col2_Count", typeof(int));
table.Columns.Add("Col3", typeof(string));
table.Columns.Add("Col3_Count", typeof(int));
Then i execute SqlCommand SELECT and add rows to table and then
chart1.DataBind();
firstly, be sure you put the Charttype as Column in chart control like ChartType="Column",
then, the XValueMember should be the same column, and Bindpoints to series with seperate dataview, like
DataView sDt1 = table .DefaultView.ToTable(true, new[] { "Column_Identifier", "RecordCount" }).DefaultView;
Series[0].Points.DataBindXY(sDt1, "Column_Identifier", sDt1, "RecordCount");

LINQ Query to DataTable.DataSource

I am trying to perform a LINQ query on a DataTable and show the result in another DataTable. My source DataTable looks something like this:
DataTable myDataTable = new DataTable();
myDataTable.Columns.Add("OrderID", typeof(int));
myDataTable.Columns.Add("Date", typeof(DateTime));
myDataTable.Columns.Add("UnitsPurchased", typeof(int));
The resulting DataTable looks like this when filled:
Order ID Date Units Purchased
16548 10/15/09 250
17984 11/03/09 512
20349 01/11/10 213
34872 01/15/10 175
My current LINQ query looks like this:
IEnumerable<DataRow> query = (from row in myDataTable.AsEnumerable()
where row.UnitsPurchased > 200
select new
{
row.OrderID,
row.Date,
row.UnitsPurchased
}) as IEnumerable<DataRow>;
resultDataTable.DataSource = query.CopyToDataTable<DataRow>();
Every time I run this code query is null. I can see that that the as IEnumerable<DataRow> is the culprit, but it makes no since to me since DataTable.AsEnumerable() returns an IEnumerable<DataRow>. Any help would be appreciated.
When you select new { }, you're actually getting an IEnumerable<(Anonymous Type)>, not IEnumerable<DataRow>. So your as IEnumerable<DataRow> will return null, since it can't be directly cast.
Either select new MyDataRow(constructor using values...) or something, or just do var query =... without the as cast. There's an msdn article about using CopyToDataTable with a non-DataRow generic parameter, though I haven't read it in depth, but selecting new DataRows is probably the easier solution.
Why do you have to create a new Anonymous Type. When you can simply do this .
DataTable myDataTable = new DataTable();
myDataTable.Columns.Add("OrderID", typeof(int));
myDataTable.Columns.Add("Date", typeof(DateTime));
myDataTable.Columns.Add("UnitsPurchased", typeof(int));
var datarow1 = myDataTable.NewRow();
datarow1.SetField("OrderID", 16548);
datarow1.SetField("Date", DateTime.Parse("10/10/09"));
datarow1.SetField("UnitsPurchased", 250);
var datarow2 = myDataTable.NewRow();
datarow2.SetField("OrderID", 17984);
datarow2.SetField("Date", DateTime.Parse("11/03/09"));
datarow2.SetField("UnitsPurchased", 512);
var datarow3 = myDataTable.NewRow();
datarow3.SetField("OrderID", 20349);
datarow3.SetField("Date", DateTime.Parse("01/11/10"));
datarow3.SetField("UnitsPurchased", 213);
var datarow4 = myDataTable.NewRow();
datarow4.SetField("OrderID", 34872);
datarow4.SetField("Date", DateTime.Parse("10/01/10"));
datarow4.SetField("UnitsPurchased", 175);
myDataTable.Rows.Add(datarow1);
myDataTable.Rows.Add(datarow2);
myDataTable.Rows.Add(datarow3);
myDataTable.Rows.Add(datarow4);
var filteredTable = myDataTable.AsEnumerable().OfType<DataRow>().Where(row => row.Field<int>("UnitsPurchased") > 200).Select(r => r);
resultDataTable.DataSource = filteredTable.CopyToDataTable();

Categories