How to compare two DataSet columns values in C#? - c#

In below code i want to compare two dataset column's values but its not match then also getting true this condition.so how to really compare?
if (dsEmp.Tables[0].Columns["EmpName"].ToString() == dsAllTables.Tables[2].Columns["EmpName"].ToString())
{
}

You are comparing two column-names, so "EmpName" with "EmpName" which is always true. Tables[0].Columns["EmpName"] returns a DataColumn with that name and ToString returns the name of the column which is "EmpName". So that's pointless.
If you instead want to know if two tables contain the same EmpName value in one of their rows you can use LINQ:
var empRowsEmpName = dsEmp.Tables[0].AsEnumerable().Select(r => r.Field<string>("EmpName"));
var allRowsEmpName = dsAllTables.Tables[2].AsEnumerable().Select(r => r.Field<string>("EmpName"));
IEnumerable<string> allIntersectingEmpNames = empRowsEmpName.Intersect(allRowsEmpName);
if (allIntersectingEmpNames.Any())
{
}
Now you even know which EmpName values are contained in both tables. You could use a foreach-loop:
foreach(string empName in allIntersectingEmpNames)
Console.WriteLine(empName);
If you want to find out if a specific value is contained in both:
bool containsName = allIntersectingEmpNames.Contains("SampleName");
If you just want to get the first matching:
string firstIntersectingEmpName = allIntersectingEmpNames.FirstOrDefault();
if(firstIntersectingEmpName != null){
// yes, there was at least one EmpName that was in both tables
}

If you have a single row, this should work:
if (dsEmp.Tables[0].Row[0]["EmpName"].ToString() == dsAllTables.Tables[2].rows[0]["EmpName"].ToString())
{
}
For multiple rows you have to iterate through table:
for (int i = 0; i <= dsEmp.Tables[0].Rows.Count; i++)
{
for (int j = 0; j <= dsAllTables.Tables[0].Rows.Count; j++)
{
if (dsEmp.Tables[0].Rows[i]["EmpName"].ToString() == dsAllTables.Tables[2].Rows[j]["EmpName"].ToString())
{
}
}
}

I have two datatables - dtbl and mtbl, and I use this to return records that have a difference, as another DataTable.
//compare the two datatables and output any differences into a new datatable, to return
var differences = dtbl.AsEnumerable().Except(mtbl.AsEnumerable(), DataRowComparer.Default);
return differences.Any() ? differences.CopyToDataTable() : new DataTable();

Related

Compare results from two selects using oracle and C#

I'm writting a C# application that compares if the result from two different selects are the same and they're execution time, for optimitzing purposes.
Actually I'm using stopwatch to get execution time and then convert OracleDataReaders into DataTable and compare rows, with independency of order, like this:
var tableA = new DataTable();
tableA.Load(readerA);
var tableB = new DataTable();
tableB.Load(readerB);
bool equals = true;
for (int i = 0; i < tableA.Rows.Count; i++)
{
if (!DataRowComparer.Default.Equals(tableA.Rows[i],tableB.Rows[i]))
{
equals = false;
break;
}
}
return equals;
But I'm assuming that converting OracleDataReader into DataTable and then using a loop to compare rows are the same and in the same order.
Is there any prebuilt method with C# and Oracle to compare result of two selects with/without rows order?
Thanks
Here is an attempt at writing a generic data comparison method for two OracleDataReaders. The code compares the readers line by line, column by column to spot any differences. It takes into account that readers may contain results from more than one query. Code will need to be enhanced if more complex datatypes (binary etc) would be compared. The code also makes the assumption that the order of the data matters; if readers are to be considered equal even when differently sorted the code would need to be rewritten to put rows into lists or dictionaries etc.
private bool ReadersContainEqualData(OracleDataReaders readerA, OracleDataReaders readerB)
{
bool moreResultsA = false;
bool moreResultsB = false;
do {
if(readerA.FieldCount != readerB.FieldCount)
{
return false; // the readers have different number of columns
}
while(readerA.Read() && readerB.Read())
{
for(int i = 0; i < readerA.FieldCount; i++)
{
if(readerA.GetName(i) != readerB.GetName(i)) // different column names, remove this check if it is not important to you
{
return false;
}
if(readerA[i] != readerB[i]) // the columns are either string, numeric or booean, so simple equals comparison works. If more complex columns like varbinary etc is used, this check will need to be enhanced
{
return false;
}
}
}
if(readerA.Read() || readerB.Read()) // one of the readers still has more rows and the other is empty
{
return false;
}
// check if the readers contains results from another query than the recently processed
moreResultsA = readerA.NextResult();
moreResultsB = readerB.NextResult();
if(moreResultsA != moreResultsB)
{
return false;
}
} while(moreResultsA && moreResultsB);
return true;
}

Test for an empty DataRow in C#

what I'm trying to do: I have a large datatable, and I'm going through a list of strings where some of them are in the datatable and some aren't. I need to make a list of those that are, and count those that aren't.
This is my code part:
DataRow[] foundRows;
foundRows = DTgesamt.Select("SAP_NR like '%"+SAP+"%'");
if (AreAllCellsEmpty(foundRows[0]) == false && !(foundRows[0]==null))
{
list.Add(SAP);
}
else
{
notfound++;
}
public static bool AreAllCellsEmpty(DataRow row)
{
if (row == null) throw new ArgumentNullException("row");
for (int i = row.Table.Columns.Count - 1; i >= 0; i--)
{
if (!row.IsNull(i))
{
return false;
}
}
return true;
}
DTgesamt ist a large DataTable. "SAP" is a string that is in the first column of the DataTable, but not all of them are included. I want to count the unfound ones with the int "notfound".
The problem is, the Select returns an empty DataRow {System.Data.DataRow[0]} when it finds nothing.
I'm getting the errormessage Index out of array area.
The two statements in the if-clause are what I read on the internet but they don't work. With only the 2nd statement it just adds all numbers to the list, with the first it still gives this error.
Thanks for any help :)
check count of items in foundRows array to avoid IndexOutOfRange exception
foundRows = DTgesamt.Select("SAP_NR like '%"+SAP+"%'");
if (foundRows.Length > 0 && AreAllCellsEmpty(foundRows[0])==false)
list.Add(SAP);
else
notfound++;
The found cells cannot be empty. Your select statement would be wrong. So what you actually need is:
if (DTgesamt.Select("SAP_NR like '%"+SAP+"%'").Any())
{
list.Add(SAP);
}
else
{
notfound++;
}
You probably don't even need the counter, when you can calculate the missed records based on how many SAP numbers you had and how many results you got in list.
If you have an original list or array of SAP numbers, you could shorten your whole loop to:
var numbersInTable = originalNumbers.Where(sap => DTgesamt.Select("SAP_NR like '%"+sap+"%'").Any()).ToList();
var notFound = originalNumbers.Count - numbersInTable.Count;

How to determine a row index from a datatable that shares a column with a combobox

I have a combobox and a datatable.
I've added all of the elements of one column in the datatable to the combobox items.
Now whenever the user chooses a item in the combobox, I want to go to the datatable and compare the column, if there's a match, it will do some code.
I have the following
private void comboBox8_SelectedIndexChanged(object sender, EventArgs e)
{
string str = comboBox8.SelectedItem.ToString();
int z = 0;
foreach (var row in datatable.Rows)
{
int i = 0; i++;
if (datatable.Rows[row]["Cidade"] == str)
{
z = i;
}
}
}
"Cidade" is the column name that matches the options in the combobox.
The Problem is that the code doesn't identify the ìf` condition as valid, saying there are invalid arguments
Edit: worked it around like this:
private void comboBox8_SelectedIndexChanged(object sender, EventArgs e)
{
string str = comboBox8.SelectedItem.ToString();
int z = 0;
for (int i = 0; i < DataAccess.Instance.tabelasismica.Rows.Count; i++)
{
if (DataAccess.Instance.tabelasismica.Rows[i]["Cidade"] == str)
{
z = i;
}
}
MessageBox.Show(z.ToString());
MessageBox.Show(DataAccess.Instance.tabelasismica.Rows[z]["Cidade"].ToString());
}
Standard way of doing things like this is to use data-binding. You'd simply set your ComboBox's DataSource to your DataTable. The code would roughly look like this:
comboBox8.DataSource = datatable;
comboBox8.DisplayMember = "Cidade"
comboBox8.ValueMember = "PrimaryKeyColumnOfYourTable"
Now in the SelectedIndexChanged event, you simply use comboBox8.SelectedValue property to get the ID of the selected row. If you have strongly typed DataSet, your DataTable will have a function named FindByYourPKColumn() that you can use to find the row using this ID.
datatable.Rows[row]["Cidade"] is of type object - you need to convert it to a string before comparing it to str, like this:
if (datatable.Rows[row]["Cidade"].ToString() == str)
{ ... }
Try this in place of the for loop
foreach (DataRow row in dDataAccess.Instance.tabelasismica.Rows)
{
if (row["Cidade"].ToString() == str)
{
z = dDataAccess.Instance.tabelasismica.Rows.IndexOf(row);
}
}
or
foreach (DataRow row in dataTable.Rows)
{
if (row["Cidade"].ToString() == str)
{
z = dataTable.Rows.IndexOf(row);;
}
}
Being said that, standard practice in using ComboBoxes, ListBoxes etc with datasources is to to have a distinct column in the data-table assigned as the ValueMember of the ComboBox, which makes life even easier - as suggested by #dotNET.
comboBox8.DataSource= dataTable; //the data table which contains data
comboBox8.ValueMember = "id"; // column name which you want in SelectedValue
comboBox8.DisplayMember = "name"; // column name that you need to display as text
That way you don't have to iterate through the dataTable to find the index of the row, and you can use the ID (ValueMember) to continue process as required.
Example here
#dotNET's answer is the preferred method to solve your specific problem.
However to solve the general problem find a value in a dataset your best bets are to either
Use the ADO.NET methods Find or Select e.g.
var results = dataset.Select(string.Format("Cidade = {0}",str));
if (results.Count() != 0 )
{
...
}
Or use System.Data.DataSetExtensions
if (datatable.AsEnumerable().Any( x=> x.Field<string>("Cidade") == str ))
{
....
}

DataRow: Select cell value by a given column name

I have a problem with a DataRow that I'm really struggling with.
The datarow is read in from an Excel spreadsheet using an OleDbConnection.
If I try to select data from the DataRow using the column name, it returns DBNull even though there is data there.
But it's not quite that simple.
datarow.Table.Columns[5].ColumnName returns "my column".
datarow["my column"] returns DBNull.
datarow[5] returns 500.
datarow[datarow.Table.Columns[5].ColumnName] returns DBNull. (just to make sure its not a typo!)
I could just select things from the datarow using the column number, but I dislike doing that since if the column ordering changes, the software will break.
Which version of .NET are you using? Since .NET 3.5, there's an assembly System.Data.DataSetExtensions, which contains various useful extensions for dataTables, dataRows and the like.
You can try using
row.Field<type>("fieldName");
if that doesn't work, you can do this:
DataTable table = new DataTable();
var myColumn = table.Columns.Cast<DataColumn>().SingleOrDefault(col => col.ColumnName == "myColumnName");
if (myColumn != null)
{
// just some roww
var tableRow = table.AsEnumerable().First();
var myData = tableRow.Field<string>(myColumn);
// or if above does not work
myData = tableRow.Field<string>(table.Columns.IndexOf(myColumn));
}
This must be a new feature or something, otherwise I'm not sure why it hasn't been mentioned.
You can access the value in a column in a DataRow object using row["ColumnName"]:
DataRow row = table.Rows[0];
string rowValue = row["ColumnName"].ToString();
I find it easier to access it by doing the following:
for (int i = 0; i < Table.Rows.Count-1; i++) //Looping through rows
{
var myValue = Table.Rows[i]["MyFieldName"]; //Getting my field value
}
Hint
DataTable table = new DataTable();
table.Columns.Add("Column#1", typeof(int));
table.Columns.Add("Column#2", typeof(string));
table.Rows.Add(5, "Cell1-1");
table.Rows.Add(130, "Cell2-2");
EDIT: Added more
string cellValue = table.Rows[0].GetCellValueByName<string>("Column#2");
public static class DataRowExtensions
{
public static T GetCellValueByName<T>(this DataRow row, string columnName)
{
int index = row.Table.Columns.IndexOf(columnName);
return (index < 0 || index > row.ItemArray.Count())
? default(T)
: (T) row[index];
}
}
On top of what Jimmy said, you can also make the select generic by using Convert.ChangeType along with the necessary null checks:
public T GetColumnValue<T>(DataRow row, string columnName)
{
T value = default(T);
if (row.Table.Columns.Contains(columnName) && row[columnName] != null && !String.IsNullOrWhiteSpace(row[columnName].ToString()))
{
value = (T)Convert.ChangeType(row[columnName].ToString(), typeof(T));
}
return value;
}
You can get the column value in VB.net
Dim row As DataRow = fooTable.Rows(0)
Dim temp = Convert.ToString(row("ColumnName"))
And in C# you can use Jimmy's Answer, just be careful while converting it to ToString(). It can throw null exception if the data is null
instead Use Convert.ToString(your_expression) to avoid null exception reference
for (int i=0;i < Table.Rows.Count;i++)
{
Var YourValue = Table.Rows[i]["ColumnName"];
}
Be careful on datatype. If not match it will throw an error.
var fieldName = dataRow.Field<DataType>("fieldName");
Simple solution:
Assume sqlDt contains the DataTable, then this will give you the content of the
column named "aaa" in row is:
Dim fldContent = sqlDte.Rows(iz).ItemArray(sqlDte.Columns.Item("aaa").Ordinal)
Console.WriteLine("aaa = " & fldContent)
Edited code formatting

c# doing a custom sort on a datatable

i have data in a datatable that needs to be sorted on the first column this way:
A02 BLANK0010
D02 BLANK0007
B04 BLANK0011
G05 BLANK0012
C06 BLANK0014
E08 BLANK0013
F10 BLANK0016
H12 BLANK0015
B02 G112486
C02 G125259
E02 G125257
F02 G112492
G02 G125095
H02 G112489
A03 G125090
B03 G112499
C03 G125256
D03 G002007
E03 G112494
F03 G002005
G03 G112495
H03 G002008
A04 G115717
if i do a regular sort, it will just sort like this: A02, A03, A04. but i need A02, B02, C02... etc
how can i do this>? here my code so far:
DataView view = dt.DefaultView;
view.Sort = "position";
You'll want to do a custom sort. See the following question for hints: DataView.Sort - more than just asc/desc (need custom sort)
You might want to break the first column into two separate columns.
Maybe need refactorings but solves the problem.
//group by the rows by splitting values of column
var groupBy = table.AsEnumerable()
.GroupBy(o =>
Regex.Replace(o["position"].ToString(), #"[0-9]", ""));
var dataRows = Sort(groupBy);
And Here is the Sort Method:
//yield the first row of each group
private static IEnumerable<DataRow> Sort(IEnumerable<IGrouping<string, DataRow>> groupByCollection)
{
//sort each character group(e.g. A,B) by integer part of their values
var groupings =
groupByCollection.Select(
o =>
new
{
o.Key,
Value = o.OrderBy(a => Regex.Replace(a["position"].ToString(), "[a-z]", "", RegexOptions.IgnoreCase)).ToArray()
}).ToArray();
int i = 0, j;
for (j = 0; j < groupings[i].Value.Length; j++,i=0)
for (i = 0; i < groupings.Length; i++)
{
yield return groupings[i].Value[j];
}
}
As possible way: add additional column that will first letter of first column and then sort by that column and first column.
A little primitive, but effective way (in this case):
dv.Sort = substring(field, 2, 3) + substring(field, 1, 1)

Categories