Removing duplicates in a MS Access database - c#

I was trying to remove duplicates from the table Main.
It looks like this(here in csv form):
"Record ID";Status;Placement;Private;Category;Note;Blob
for instance
14341692;132;2147483647;False;4;"29.12.10 14:17";System.Byte[]
Duplicates means, Note is the same. My approach is this:
string strSQL = "SELECT * FROM Main";
OleDbCommand cmd = new OleDbCommand(strSQL, MemoVerbindung);
OleDbDataReader dr = cmd.ExecuteReader();
_items = new List<string>(); // <-- Add this
while (dr.Read())
{
if (dr.FieldCount >= 5)
_items.Add(dr[5].ToString());
}
dr.Close();
progressBar1.Maximum = _items.Count;
for (int a = 0; a < _items.Count; a++)
{
progressBar1.Value = a;
strSQL = "SELECT * FROM Main WHERE Note = '" + _items[a].ToString().Replace("'", "\'") + "'";
cmd = new OleDbCommand(strSQL, MemoVerbindung);
dr = null;
OleDbDataReader dr2 = null;
try
{
dr = cmd.ExecuteReader();
int u = 0;
if (dr.FieldCount > 1)
{
while (dr.Read())
{
if (u >= 1)
{
string was = "DELETE FROM Main WHERE [Record ID] = " + dr[0];
OleDbCommand command = new OleDbCommand(was, MemoVerbindung);
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//MessageBox.Show(reader[0].ToString());
}
reader.Close();
}
u++;
}
}
else
{
while (dr.Read())
{
MessageBox.Show("Übrig");
}
}
dr.Close();
}
catch (Exception mm)
{
//MessageBox.Show(mm.Message);
}
}
MessageBox.Show("Fertig");
progressBar1.Value = 0;
So in the if (u >= 1) section I am trying to leave one version while removing all others. Unfortunately that does not work meaning all entries are removed but the ones raising an error for a reason. What would you change or is there a generally more elegant way?

Use this SQL statement to find the duplicates:
SELECT First(Main.[Note]) AS [NoteField], Count(Main.[Note]) AS NumberOfDups
FROM Main
GROUP BY Main.[Note]
HAVING (((Count(Main.[Note]))>1));
then you can loop through this recordset (grab it as a SnapShot so changes to the underlying data does not change the results)
use !NoteField to know which note to find, and !NumberOfDups to know how many you have to delete (remove this number - 1)

Related

invalid attempt to read when no data is present to ListBox in asp.net c#

My question is about to - Invalid attempt to read when no data is present to ListBox in asp.net c# SqDataReader
My code is :
SqlConnection oConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["evaConn"].ConnectionString);
try
{
oConn.Open();
SqlCommand oCmd = new SqlCommand();
oCmd.Connection = oConn;
oCmd.CommandText = str;
SqlDataReader dr = oCmd.ExecuteReader();
lstLeft.DataTextField = "drname";
lstLeft.DataValueField = "drid";
lstLeft.DataSource = dr;
lstLeft.DataBind();
for (int j = 0; j < lstLeft.Items.Count; j++)
{
while (dr.Read())
{
if (dr["othermr"].ToString() == "1")
{
lstLeft.Items[j].Text = lstLeft.Items[j].Text + " (Assigned to - " + dr["mrname"].ToString() + ")";
}
}
}
dr.Close();
}
catch (Exception)
{
}
finally
{
oConn.Close();
oConn.Dispose();
}
Error comes invalid attempt to read when no data is present to List Box in
asp.net c# after binding the data to Listbox
This is not a good practice to use DataReader inside for-loop:
for (int j = 0; j < lstLeft.Items.Count; j++)
{
while (dr.Read())
{
if (dr["othermr"].ToString() == "1")
{
lstLeft.Items[j].Text = lstLeft.Items[j].Text + " (Assigned to - " + dr["mrname"].ToString() + ")";
}
}
}
Note that DataReader is running in one direction so that when it exits the while loop, it reached end of loaded data sequence, thus it can't be used to get value of non-existent record when advanced to next loop (and returns invalid attempt to read when no data is present).
The correct way is using a counter inside while loop & counts every time the data has been read until the last sequence:
var dr = oCmd.ExecuteReader();
int j = 0;
while (dr.Read())
{
if (dr["othermr"].ToString() == "1")
{
lstLeft.Items[j].Text = lstLeft.Items[j].Text + " (Assigned to - " + dr["mrname"].ToString() + ")";
}
if (j == lstLeft.Items.Count)
{
break;
}
j++; // counter
}
I recommend to use DataTable if you still want to use for loop:
var dr = oCmd.ExecuteReader();
var dt = new DataTable();
dt.Load(dr); // load data into DataTable instead
for (int j = 0; j < lstLeft.Items.Count; j++)
{
// adjust the row index number so that you can get proper values
if (dt.Rows[j]["othermr"].ToString() == "1")
{
lstLeft.Items[j].Text = lstLeft.Items[j].Text + " (Assigned to - " + dt.Rows[j]["mrname"].ToString() + ")";
}
}
Additionally, when binding data source to a server control from DataReader you should use DataTable (and you can reuse it with for-loop above):
// taken from /a/14089639
using (var oCmd = new SqlCommand(str, oConn))
{
var dap = new SqlDataAdapter(oCmd);
var dt = new DataTable();
dap.Fill(dt);
lstLeft.DataTextField = "drname";
lstLeft.DataValueField = "drid";
lstLeft.DataSource = dt;
lstLeft.DataBind();
}
Note that you don't need to use oCmd.ExecuteReader() twice if on the first stage you're already putting DataReader contents inside DataTable.
Reference:
How to fill listBox Control?
Shail,
To me, your Reader becomes empty (but not null) after you bind it with Listbox.
So, if you change you code like below, i hope it will work for you:
SqlConnection oConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["evaConn"].ConnectionString);
try
{
oConn.Open();
SqlCommand oCmd = new SqlCommand();
oCmd.Connection = oConn;
oCmd.CommandText = str;
SqlDataReader dr = oCmd.ExecuteReader();
lstLeft.DataTextField = "drname";
lstLeft.DataValueField = "drid";
lstLeft.DataSource = dr;
lstLeft.DataBind();
dr.Close();//Close dr here
dr = oCmd.ExecuteReader();//fill it again here
for (int j = 0; j < lstLeft.Items.Count; j++)
{
while (dr.Read())
{
if (dr["othermr"].ToString() == "1")
{
lstLeft.Items[j].Text = lstLeft.Items[j].Text + " (Assigned to - " + dr["mrname"].ToString() + ")";
}
}
}
dr.Close();
}
catch (Exception)
{
}
finally
{
oConn.Close();
oConn.Dispose();
}

c#.net Error: There is already an open DataReader associated with this Command which must be closed first

Help, I am new to asp.net c#. I tried the codes once before but it didn't seems to have this error. So I can't seems to figure where do I make changes to.
Sever error :
There is already an open DataReader associated with this Command which must be closed first.
Codes:
string strConnectionString = ConfigurationManager.ConnectionStrings["FYPDB"].ConnectionString;
SqlConnection myConnect = new SqlConnection(strConnectionString);
string strCommandText = "select promoId FROM FYPDB.dbo.Promotions where membershipType LIKE '%' + #membership + '%' AND defaults LIKE '%' + #defaults + '%'";
try
{
string ddlmembership = ((DropDownList)dvInsertPromotion.FindControl("ddlAddMembershiplist")).SelectedItem.ToString();
string ddlDefault = ((RadioButtonList)dvInsertPromotion.FindControl("RadioButtonList2")).Text.ToString();
DataSet da = dal.retrieveMembership(ddlmembership, ddlDefault);
SiteGridView.DataSource = da;
SiteGridView.DataBind();
SqlCommand cmd = new SqlCommand(strCommandText, myConnect);
cmd.Parameters.Add("#membership", SqlDbType.NVarChar);
cmd.Parameters.Add("#defaults", SqlDbType.NVarChar);
cmd.Parameters["#membership"].Value = ddlmembership;
cmd.Parameters["#defaults"].Value = ddlDefault;
myConnect.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
//get number of count
//int count = da.Tables[0].Rows.Count;
int count = (int)cmd.ExecuteScalar();
if (count == 1)
{
defaultComfirm.Show();
promotion = false;
}
}
else
{
Label6.Text = "error didnt go through";
Label6.ForeColor = System.Drawing.Color.Gray;
Label6.Visible = true;
}
reader.Close();
}
finally
{
myConnect.Close();
}
you are using the same command object two times:
SqlDataReader reader = cmd.ExecuteReader();
int count = (int)cmd.ExecuteScalar();
This is not possible.
It is not necessary to use a reader if you just want to have the count of rows. In this case you can use the ExecuteScalar.
Like this:
string strCommandText = "select COUNT(promoId) FROM FYPDB.dbo.Promotions where membershipType LIKE '%' + #membership + '%' AND defaults LIKE '%' + #defaults + '%'";
try
{
...
int count = (int)cmd.ExecuteScalar();
...
Regards
Oliver
Looking at your code, you just need count of rows matching the criteria.
So if you just need rows count you could use any of these options.
Option 1:
Find out count by reading all rows
int count =0;
while(reader.Read()) count++;
if (count == 1)
{
defaultComfirm.Show();
promotion = false;
}
else
{
...
}
reader.Close();
Option 2:
My preferred choice for this case, Modify your query to return the count (SELECT COUNT(*)).
string strCommandText = "select count(promoId) FROM FYPDB.dbo.Promotions where membershipType LIKE '%' + #membership + '%' AND defaults LIKE '%' + #defaults + '%'";
now,
int count = (int)cmd.ExecuteScalar();
if (count == 1)
{
defaultComfirm.Show();
promotion = false;
}
else
{
...
}
reader.Close();
Option 3:
Other option to convert it to DataTable and get the row count.
using (DataTable dt = new DataTable())
{
dt.Load(reader);
if (dt.Rows.Count == 1)
{
defaultComfirm.Show();
promotion = false;
}
else
{
...
}
reader.Close();
}
try to execute cmd.ExecuteScalar() before cmd.ExecuteReader().
int count = (int)cmd.ExecuteScalar();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
//get number of count
//int count = da.Tables[0].Rows.Count;
if (count == 1)
{
defaultComfirm.Show();
promotion = false;
}
}

Convert Rank to percentage C#

I am trying to display percentage based on the rank of each record returned in search. I want it to loop through each item but it only loops through the first item as many times as I have items. For instance if it found 4 results it would display the rank of the first one on all 4 results.
Any suggestions to get it to display each rank separately and convert it to percentage?
private void BindRpt()
{
if (string.IsNullOrEmpty(txtSearch.Text)) return;
SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DB"].ConnectionString);
cn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
cmd.CommandText = "select Distinct Rank, SUBSTRING(ColumnA, 1, 500) AS ColumnA, ColumnB, ColumnC, ColumnD, ColumnE from FREETEXTTABLE (TABLE , ColumnA, '" + Search.Text + "' ) S, TABLE C WHERE c.ID = S.[KEY] order by Rank Desc";
DataTable dt = new DataTable();
adapter.SelectCommand = cmd;
adapter.Fill(dt);
PagedDataSource pgitems = new PagedDataSource();
pgitems.DataSource = dt.DefaultView;
pgitems.AllowPaging = true;
pgitems.PageSize = 3;
pgitems.CurrentPageIndex = PageNumber;
if (pgitems.Count > 1)
{
rptPaging.Visible = true;
ArrayList pages = new ArrayList();
for (int i = 0; i <= pgitems.PageCount - 1; i++)
{
pages.Add((i + 1).ToString());
}
rptPaging.DataSource = pages;
rptPaging.DataBind();
lblSentence.Visible = true;
lblSearchWord.Visible = true;
lblSearchWord.Text = txtSearch.Text;
}
else
{
rptPaging.Visible = false;
lblSentence.Visible = true;
lblSentence.Text = "Results were found for";
lblSearchWord.Visible = true;
lblSearchWord.Text = txtSearch.Text;
}
rptResults.DataSource = pgitems;
rptResults.DataBind();
cn.Close();
}
protected void rptResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["HTAA"].ConnectionString);
cn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
cmd.CommandText = "select Distinct Rank, SUBSTRING(ColumnA, 1, 500) AS ColumnA, ColumnB, ColumnC, ColumnD, ColumnE from FREETEXTTABLE (TABLE , ColumnA, '" + Search.Text + "' ) S, TABLE C WHERE c.ID = S.[KEY] order by Rank Desc";
int number = Page.Items.Count;
SqlDataReader dr = cmd.ExecuteReader();
if(dr.Read())
{
int firstrank = dr.GetInt32(0);
while (dr.Read())
{
int rank = dr.GetInt32(0);
int percentage = (rank / firstrank) * 100;
Label lblpre = (Label)e.Item.FindControl("lblRank");
lblpre.Text = percentage.ToString();
}
}
dr.Close();
cn.Close();
}
After a chat, I have a better handle on things. A way to do this;
Create a private field on your code behind file.
private int topRanked = 0;
In your Bind method()
private void Bind()
{
...
DataTable dt = new DataTable();
adapter.SelectCommand = cmd;
adapter.Fill(dt);
topRanked = (int)dt.Rows[0]["Rank"];
Now, make your OnItemDataBound method;
protected void OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
var dataItem = e.Item.DataItem as DataRowView;
int rank = (int) dataItem["Rank"];
var percentage = ((double)topRanked / rank) * 100;
Label label = (Label)e.Item.FindControl("labelRank");
label.Text = percentage.ToString();
}
as mentioned. I don't believe it's the best answer, but it is an answer. I'm sure a stored procedure, or even a better sql method could probably calculate this and not leave you making calculations in code.
Can you try with while(dr.Read()) instead of "if"?
You will want to loop over the result set
while (dr.Read())
{
int rank = dr.GetInt32(0);
int percentage = (rank / rank) * 100;
Label lblpre = (Label)e.Item.FindControl("lblRank");
lblpre.Text = rank.ToString();
}
"but it only loops through the first item" - because you have a for and checks for i <= 0
for (int i = 0; i <= 0; i++)
{
....
}
You just don't need this for statement but rather use
if (dr != null)
using (dr)
{
while (dr.Read())
{
..
}
}
It's always better to use using when dealing with db connection objects so the resources used by these objects are properly disposed after it's been used.

select all from access and place in string

I'm having trouble selecting all items from my access database. I want to select the data in the entire row and keep it in a string, separating each item by a ";". Below is the code i have that will give me the column i specify, but i want all the data in the row.
con.Open();
type= checkBox49.Text;
String str = "Select * from distro where type='" + type + "'";
cmd = new OleDbCommand(str, con);
dr = cmd.ExecuteReader();
if (dr.Read())
{
str2 = dr.GetString(1);
}
You can try something like this where columnsCount is the number of your columns in your database table
if (dr.Read())
{
for (int i = 0; i <columnsCount; i++)
{
str2 += string.Join(";",sdr.GetString(i));
}
}
You could select each field by name and combine them together like
str2 = dr["FieldName"].ToString() + "." + dr["FieldName"].ToString();
Also, I wouldn't reference any fields by number, but by FieldName.
So one approach, with the current code, would be this:
StringBuilder sb = new StringBuilder();
if (dr.Read())
{
for (int i = 0; i < dr.FieldCount; i++)
{
if (sb.Length > 0) { sb.Append(";"); }
sb.Append(dr.GetString(i));
}
}
A more global code if all your columns are not string type :
var con = new OleDbConnection();
var cmd = new OleDbCommand(str, con);
var dr = cmd.ExecuteReader();
var res = string.Empty;
if (dr.Read())
{
object[] t = new Object[dr.FieldCount];
if (dr.GetValues(t)>0)
{
res = String.Join(";", (from el in t select el as string).Where(x => x!=null).ToArray());
}
}
return res;
You could just string.Join all the values together.
con.Open();
type = checkBox49.Text;
String str = "Select * from distro where type=?";
cmd = new OleDbCommand(str, con);
cmd.Parameters.Add(type);
using (dr = cmd.ExecuteReader())
{
if (dr.Read())
{
var values = new object[dr.FieldCount];
dr.GetValues(values);
str2 = string.Join(";", values.Skip(1).Select(d => d.ToString());
}
}
Notice the use of a parameter in the query too. Standard way to avoid SQL Injection.

SqlDataReader in C#

I have a problem with SqlDataReader.
Here's my code. the problem is when I debug it it doesn't go further than
while(dr.read())
it means the value returned by dr.Read() is false. I don't know what's wrong.
if (CS_time_date[i].Substring(0, 2) == "CS")
{
string cardserial = CS_time_date[i].Substring(4, 5);
try
{
using (SqlConnection con = new SqlConnection(WindowsAppEmp.Properties.Settings.Default.Database1ConnectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand("select * from Card_reg ", con);
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
if ((dr["Cardserial"].ToString() == cardserial))
{
flag = 1;
string EmpID = dr["Id"].ToString();
string F_Name = dr["fname"].ToString();
string L_Name = dr["lname"].ToString();
// Insert_EmpReport(EmpID, F_Name, L_Name, cardserial, CS_time_date,con);
string strsql1 = "Insert into Emp_Report (EmpId,CS,fname,lname,CheckIn,CheckOut,Date,Status) values (#EmpID,#Cs,#fname,#lname,#CheckIn,#CheckOut,#Date,#Status)";
SqlCommand report_cmd = new SqlCommand(strsql1, con);
report_cmd.Parameters.AddWithValue("#EmpID", EmpID);
report_cmd.Parameters.AddWithValue("#Cs", cardserial);
report_cmd.Parameters.AddWithValue("#fname", F_Name);
report_cmd.Parameters.AddWithValue("#lname", L_Name);
if (CS_time_date[i].Substring(9, 10) == "56")
if (CS_time_date[i + 2] == DateTime.Now.ToString("dd/mm/yyyy"))
{
report_cmd.Parameters.AddWithValue("#CheckIn", CS_time_date[i + 1]);
report_cmd.Parameters.AddWithValue("#Status", "Present");
}
else
report_cmd.Parameters.AddWithValue("#Status", "Absent");
else
report_cmd.Parameters.AddWithValue("#CheckOut", CS_time_date[i + 1]);
report_cmd.Parameters.AddWithValue("#Date", CS_time_date[i + 2]);
}
else
flag = 0;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
} while (reader.Peek() != -1);
reader.Close();
It looks like you have the Card_reg table defined in your database but this table doesn't contain any values in it - it is empty. That's why the select * from Card_reg query doesn't return any results and the data reader has nothing to read.

Categories

Resources