Get count of two joined data tables - c#

I have two data tables in my C# code, each with a single column called ID of type string.
I want to (inner) join the two tables on the ID column and get a count of the common rows. I don't need the IDs themselves, just the count of common IDs.
One of the tables may have duplicate IDs but the join must consider only distinct values so if there are two rows with ID=544 they should only count as one.
The two tables may have over a million rows each so performance is an issue. What would be the simplest and most efficient way to code this in C#?

It needs a simple inner join. If i understood you properly here i have given the solution. Try it and let me know if it solves your problem
using System;
using System.Linq;
using System.Data;
namespace JoinDatatablesConsoleApp
{
class Program
{
static void Main(string[] args)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("ID", typeof(string));
DataTable dt2 = new DataTable();
dt2.Columns.Add("ID", typeof(string));
for(int i=1;i<5;i++)
{
DataRow dr1 = dt1.NewRow();
dr1["ID"] = i + "A";
dt1.Rows.Add(dr1);
DataRow dr2 = dt2.NewRow();
dr2["ID"] = i + "A";
dt2.Rows.Add(dr2);
}
DataRow dr3 = dt2.NewRow();
dr3["ID"] = "7A";
dt2.Rows.Add(dr3);
var commonData = (from f1 in dt1.AsEnumerable()
join f2 in dt2.AsEnumerable()
on f1.Field<string>("ID")
equals f2.Field<string>("ID")
select f1.Field<string>("ID"))
.Distinct().ToList();
Console.WriteLine("Common Data : ");
foreach(var item in commonData)
{
Console.WriteLine(item);
}
Console.WriteLine("Common Data Count : " + commonData.Count);
Console.Read();
}
}
}

Related

Ordering a DataTable in Descending Order using Multiple Columns C#

I want to create a method which is able to take a Datatable and order the rows in descending order via multiple columns specified.
Below is an example of when I call the table sorting method:
t1 = getSortedTable(t1 , "Hotel Costs, Flight Cost DESC");
The Hotel Costs and Flight Costs are both type Double columns. The method for sorting is as below:
public static DataTable getSortedTable(DataTable dt, string sort)
{
DataTable newTable = new DataTable();
newTable = dt.Clone();
newTable.Rows.Clear();
DataRow[] newRows = dt.Select("", sort);
foreach (DataRow nr in newRows)
{
newTable.Rows.Add(nr.ItemArray);
}
return newTable;
}
The method only returns a table with rows sorted via the Flight Cost in descending order.
You can specify the DefaultView with the sort parameters and just return that view ToTable():
public static DataTable GetSortedTable(DataTable dt, string sort)
{
dt.DefaultView.Sort = sort;
return dt.DefaultView.ToTable();
}
EDIT: There's a chance that having spaces in your column names will interfere with the sort so you can either rename your column names like so:
foreach(var column in dt.Columns)
{
column.ColumnName = column.ColumnName.Replace(" ", "_");
}
Or use linq
if (dt.Rows.Count > 0)
{
dt = dt.AsEnumerable().OrderByDescending(x=>x.Field<decimal>("Hotel Costs")).ThenByDescending(x=>x.Field<decimal>("Flight Costs"))
.Select(x=>x)
.CopyToDataTable();
}

input array is longer than the number of columns in this table

I have defined a dataTable Like this
DataTable dtFinal = new DataTable();
dtFinal.Columns.Add("AVNR", typeof(int));
dtFinal.Columns.Add("Substation", typeof(string));
dtFinal.Columns.Add("ColumnTitle", typeof(string));
dtFinal.Columns.Add("S6_NAME", typeof(string));
dtFinal.Columns.Add("Voltage", typeof(string));
dtFinal.Columns.Add("Wert", typeof(decimal));
and I make a join between two tables to have a result set
var results = from table1 in dtTimeListTable.AsEnumerable()
join table2 in readyDataTable.AsEnumerable() on (decimal)table1["Avnr"] equals (int)table2["Avnr"]
select new
{
AVNR = (int)table2["AVNR"],
Substation = (string)table2["Substation"],
ColumnTitle = (string)table2["ColumnTitle"],
S6_NAME = (string)table2["S6_NAME"],
Voltage = (string)table2["Voltage"],
Wert = (decimal)table1["Wert"]
};
to fill datatable up I do the following:
dtFinal.Rows.Add(results.ToArray());
but I'll get a error liek this
input array is longer than the number of columns in this table
both datatable have 6 columns, what could be the problem?
DataRowCollection.Add is a method to add a single DataRow but you are trying to add all rows.
You need a loop:
foreach(var x in query)
dtFinal.Rows.Add(x.AVNR, x.Substation, x.ColumnTitle, x.S6_NAME, x.Voltage, x.Wert);
You could build the object[] for each DataRow also in this way:
var joinedRows = from table1 in dtTimeListTable.AsEnumerable()
join table2 in readyDataTable.AsEnumerable() on (decimal) table1["Avnr"] equals (int) table2["Avnr"]
select new { r1 = table1, r2 = table2 };
foreach (var x in joinedRows)
{
object[] fields =
{
x.r2.Field<int>("AVNR"), x.r2.Field<string>("Substation"), x.r2.Field<string>("ColumnTitle"),
x.r2.Field<int>("S6_NAME"), x.r2.Field<string>("Voltage"), x.r1.Field<decimal>("Wert"),
};
dtFinal.Rows.Add(fields);
}

Getting common ID from two DataTables

I have two DataTables : dt1 & dt2. dt1 contains one field, ID and dt2 contains two fields, ass_ID and Name.
I have to get the number of matched IDs from these two DataTables. How do I do this? Any easy way to compare them or anything to get the count of matched IDs (common IDs) in both of these tables?
var count = (from dr1 in dt.AsEnumerable()
from dr2 in dt2.AsEnumerable()
where dr1.Field<int>("ID") == dr2.Field<int>("ass_ID")
select dr1).Count();
Or
var count = (from dr1 in dt1.AsEnumerable()
join j in dt2.AsEnumerable() on dr1.Field<int>("ID") equals j.Field<int>("ass_ID")
select j).Count();
Try this:
string strExpression = string.Format("ID = '{0}'",dt2.Columns["ass_ID"]);
DafaultView dv = new DefaultView();
dv = dt1.DefaultView;
dv.RowFilter = strExpression;
//work with dv (DefaultView)

replace all occurrences in a datatable with a value in another data table

is there any way to replace all occurrences of a value in a data table with another value from a different data table.for example I have two data table one has Itemid and another has itemid and item name.I need to replace item id in first data table with the item name from the second data table..Is there any possible way to replace all occurances at one go or should i go for the usual loop method and use Datatable.Select method.Please help.Thanks in advance.
What about this? (I realise it is a loop - but very compact and any built in method would loop anyway, just behind the scenes)
//Build first Test DT
DataTable dt1 = new DataTable();
dt1.Columns.Add("itemID", typeof(string));
//Build Second Test DT
DataTable dt2 = new DataTable();
dt2.Columns.Add("itemID", typeof(string));
dt2.Columns.Add("itemName", typeof(string));
//aad 3 DataRows to first DT - ID only
DataRow dt1_1 = dt1.NewRow();
dt1_1["itemID"] = "1";
DataRow dt1_2 = dt1.NewRow();
dt1_2["itemID"] = "2";
DataRow dt1_3 = dt1.NewRow();
dt1_3["itemID"] = "3";
dt1.Rows.Add(dt1_1);
dt1.Rows.Add(dt1_2);
dt1.Rows.Add(dt1_3);
//aad 3 DataRows to first DT - ID & Name
DataRow dt2_1 = dt2.NewRow();
dt2_1["itemID"] = "1";
dt2_1["itemName"] = "ItemOne";
DataRow dt2_2 = dt2.NewRow();
dt2_2["itemID"] = "2";
dt2_2["itemName"] = "ItemTwo";
DataRow dt2_3 = dt2.NewRow();
dt2_3["itemID"] = "3";
dt2_3["itemName"] = "ItemThree";
dt2.Rows.Add(dt2_1);
dt2.Rows.Add(dt2_2);
dt2.Rows.Add(dt2_3);
////////////////////////////////////////////////////////
//replacing code - quite comact - assumed itemId is PK//
////////////////////////////////////////////////////////
foreach (DataRow dr in dt1.Rows)
{
string strSelect = "[itemID] = '"+ dr["itemID"] +"'";
DataRow[] myRow = dt2.Select(strSelect);
if (myRow.Length == 1)
{
dr["itemID"] = myRow[0]["itemName"];
}
}
/////////////////////////////////////////////////////////////////
//dt1 now has itemOne, itemTwo and itemThree instead of 1, 2, 3//
/////////////////////////////////////////////////////////////////
With MySQL I would try:
UPDATE table1 t1, table2 t2
SET t1.itemid = t2.itemname
WHERE t1.itemid = t2.itemid
With MS-SQL I would try
UPDATE t1
SET t1.itemid = t2.itemname
FROM table1 t1 INNER JOIN table2 t2
ON t1.itemid = t2.itemid

Sorting rows in a data table

We have two columns in a DataTable, like so:
COL1 COL2
Abc 5
Def 8
Ghi 3
We're trying to sort this datatable based on COL2 in decreasing order.
COL1 COL2
ghi 8
abc 4
def 3
jkl 1
We tried this:
ft.DefaultView.Sort = "COL2 desc";
ft = ft.DefaultView.ToTable(true);
but, without using a DataView, we want to sort the DataTable itself, not the DataView.
I'm afraid you can't easily do an in-place sort of a DataTable like it sounds like you want to do.
What you can do is create a new DataTable from a DataView that you create from your original DataTable. Apply whatever sorts and/or filters you want on the DataView and then create a new DataTable from the DataView using the DataView.ToTable method:
DataView dv = ft.DefaultView;
dv.Sort = "occr desc";
DataTable sortedDT = dv.ToTable();
This will help you...
DataTable dt = new DataTable();
dt.DefaultView.Sort = "Column_name desc";
dt = dt.DefaultView.ToTable();
Its Simple Use .Select function.
DataRow[] foundRows=table.Select("Date = '1/31/1979' or OrderID = 2", "CompanyName ASC");
DataTable dt = foundRows.CopyToDataTable();
And it's done......Happy Coding
Maybe the following can help:
DataRow[] dataRows = table.Select().OrderBy(u => u["EmailId"]).ToArray();
Here, you can use other Lambda expression queries too.
Or, if you can use a DataGridView, you could just call Sort(column, direction):
namespace Sorter
{
using System;
using System.ComponentModel;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.dataGridView1.Rows.Add("Abc", 5);
this.dataGridView1.Rows.Add("Def", 8);
this.dataGridView1.Rows.Add("Ghi", 3);
this.dataGridView1.Sort(this.dataGridView1.Columns[1],
ListSortDirection.Ascending);
}
}
}
Which would give you the desired result:
Did you try using the Select(filterExpression, sortOrder) method on DataTable? See here for an example. Note this method will not sort the data table in place, if that is what you are looking for, but it will return a sorted array of rows without using a data view.
table.DefaultView.Sort = "[occr] DESC";
Use LINQ - The beauty of C#
DataTable newDataTable = baseTable.AsEnumerable()
.OrderBy(r=> r.Field<int>("ColumnName"))
.CopyToDataTable();
There is 2 way for sort data
1) sorting just data and fill into grid:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
DataTable dt2 = new DataTable(); // temp data table
DataRow[] dra = dt1.Select("", "ID DESC");
if (dra.Length > 0)
dt2 = dra.CopyToDataTable();
datagridview1.DataSource = dt2;
2) sort default view that is like of sort with grid column header:
DataGridView datagridview1 = new DataGridView(); // for show data
DataTable dt1 = new DataTable(); // have data
dt1.DefaultView.Sort = "ID DESC";
datagridview1.DataSource = dt1;
It turns out there is a special case where this can be achieved. The trick is when building the DataTable, collect all the rows in a list, sort them, then add them. This case just came up here.
//Hope This will help you..
DataTable table = new DataTable();
//DataRow[] rowArray = dataTable.Select();
table = dataTable.Clone();
for (int i = dataTable.Rows.Count - 1; i >= 0; i--)
{
table.ImportRow(dataTable.Rows[i]);
}
return table;
TL;DR
use tableObject.Select(queryExpression, sortOrderExpression) to select data in sorted manner
Complete example
Complete working example - can be tested in a console application:
using System;
using System.Data;
namespace A
{
class Program
{
static void Main(string[] args)
{
DataTable table = new DataTable("Orders");
table.Columns.Add("OrderID", typeof(Int32));
table.Columns.Add("OrderQuantity", typeof(Int32));
table.Columns.Add("CompanyName", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
DataRow newRow = table.NewRow();
newRow["OrderID"] = 1;
newRow["OrderQuantity"] = 3;
newRow["CompanyName"] = "NewCompanyName";
newRow["Date"] = "1979, 1, 31";
// Add the row to the rows collection.
table.Rows.Add(newRow);
DataRow newRow2 = table.NewRow();
newRow2["OrderID"] = 2;
newRow2["OrderQuantity"] = 2;
newRow2["CompanyName"] = "NewCompanyName1";
table.Rows.Add(newRow2);
DataRow newRow3 = table.NewRow();
newRow3["OrderID"] = 3;
newRow3["OrderQuantity"] = 2;
newRow3["CompanyName"] = "NewCompanyName2";
table.Rows.Add(newRow3);
DataRow[] foundRows;
Console.WriteLine("Original table's CompanyNames");
Console.WriteLine("************************************");
foundRows = table.Select();
// Print column 0 of each returned row.
for (int i = 0; i < foundRows.Length; i++)
Console.WriteLine(foundRows[i][2]);
// Presuming the DataTable has a column named Date.
string expression = "Date = '1/31/1979' or OrderID = 2";
// string expression = "OrderQuantity = 2 and OrderID = 2";
// Sort descending by column named CompanyName.
string sortOrder = "CompanyName ASC";
Console.WriteLine("\nCompanyNames data for Date = '1/31/1979' or OrderID = 2, sorted CompanyName ASC");
Console.WriteLine("************************************");
// Use the Select method to find all rows matching the filter.
foundRows = table.Select(expression, sortOrder);
// Print column 0 of each returned row.
for (int i = 0; i < foundRows.Length; i++)
Console.WriteLine(foundRows[i][2]);
Console.ReadKey();
}
}
}
Output
try this:
DataTable DT = new DataTable();
DataTable sortedDT = DT;
sortedDT.Clear();
foreach (DataRow row in DT.Select("", "DiffTotal desc"))
{
sortedDT.NewRow();
sortedDT.Rows.Add(row);
}
DT = sortedDT;
Yes the above answers describing the corect way to sort datatable
DataView dv = ft.DefaultView;
dv.Sort = "occr desc";
DataTable sortedDT = dv.ToTable();
But in addition to this, to select particular row in it you can use LINQ and try following
var Temp = MyDataSet.Tables[0].AsEnumerable().Take(1).CopyToDataTable();

Categories