How to get multiple rows from access database - c#

I am trying to store each row of a access database, based on column Veh_ID. The found data may or may not be based on multiple rows. The code I am currently using can copy single row but if there are multiple results I can only get the first result. Can anyone please help me on this? I am noob when it comes to database. I tried to search Google but no one seems to be needing what I need. Here's the code I'm using:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
read.Read();
veh_id=null;
int i=0;
foreach (var a in read)
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
i++;
}

There are a few things I would point out, some specific to your question, some not:
USE PARAMETERISED QUERIES
Use OleDbDataReader.Read() to move to the next record.
Use a StringBuilder to concatenate strings in a loop, using string = string + "something" will create a new string on the heap with each iteration
Use using blocks on Disposable objects
catch { } is not good practice. You will never know an error occurred. At the very least you should log the error somewhere so you know you need to fix something.
OleDbDataReader[i] will get the data from column i for the current record being read, not the data from row i
Don't use SELECT * in production code, especially if you are only using 1 column. It is unnecessary data retrieval from the database and also unnecessary network traffic.
USE PARAMETERISED QUERIES
Okay, I know I included using parameterised queries twice, but that is how strongly I feel about it!
With the above changes made, your full code will become something like:
static string GetStringData(string vehID)
{
StringBuilder builder = new StringBuilder();
string cmd1 = "SELECT Column1 FROM Veh_checkup WHERE Veh_ID = #VehID";
using (OleDbConnection con = new OleDbConnection("YourConnectionString"))
using (OleDbCommand cmd = new OleDbCommand(cmd1, con))
{
con.Open();
cmd.Parameters.AddWithValue("#VehID", vehID);
using (OleDbDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
builder.Append(" " + reader.GetString(0));
}
}
}
return builder.ToString();
}

You are using the datareader in a wrong way. Instead of calling it once like you do, you have to call the datareader in a while loop like this:
while(theDataReader.Read())
{
// do your stuff in a loop now
}
So using this approach in your code would look something like this:
string cmd1 = "SELECT * FROM Veh_checkup WHERE Veh_ID = " + veh_idd + "";
OleDbCommand cmd = new OleDbCommand(cmd1, con);
OleDbDataReader read = cmd.ExecuteReader();
veh_id=null;
con.Open();
while(read.Read()) //your reader
{
try
{
veh_id = veh_id + " " + read[i].ToString();
}
catch { }
}

Related

cek valid data in table with input ";" and where in

i want to check valid data...
i have a table Divisi with sample data like this:
=====================
IdDivisi NamaDivisi
=====================
1 DivisiA
2 DivisiB
3 DivisiC
in my code, i get value :
string data = DivisiA;DivXXX
so, when checked, the alert will appear invalid data.
I want to get a query like this:
select NamaDivisi from Divisi where NamaDivisi IN('DivisiA','DivXXX')
and the result is null or empty or invalid.
because there are values ​​/ data 'DivXXX' is not valid on the table Divisi
But this time, when I debug, I get the query result like this:
select NamaDivisi from Divisi where NamaDivisi IN ('DivisiA;DivXXX')
===================================================
This is the full code.
private string CekValidDivisi(string data)
{
DivisiFacade div = new DivisiFacade();
string getDivisi = div.CekValidData(data);
return getDivisi;
}
public string CekValidData(string data)
{
SqlConnection Conn = DataSetting.GetSqlConnection();
SqlCommand Comm = new SqlCommand();
try
{
Conn.Open();
string sql = #"select NamaDivisi from Divisi where NamaDivisi IN('" + data + "')";
Comm = new SqlCommand(sql, Conn);
data = Convert.ToString(Comm.ExecuteScalar());
}
finally
{
Conn.Close();
Conn.Dispose();
}
return data;
}
please help me to resolve the problem in my code. thank you ...
You have multiple problems in your code, but this is not a place to teach you basics, so I'll try to stick to the topic. If you want to have a parameter like that, you have to create it like that first. I guess the data contains string with value DivisiA;DivXXX (and I presume DivXXX is just a generic name meaning you have multiple divisions there). Probably the easiest way would be to do something like this with it
public string CekValidData(string data)
{
SqlConnection Conn = DataSetting.GetSqlConnection();
SqlCommand Comm = new SqlCommand();
try
{
Conn.Open();
string paramData = ParseData(data);
string sql = #"select NamaDivisi from Divisi where NamaDivisi IN('" + paramData + "')";
Comm = new SqlCommand(sql, Conn);
data = Convert.ToString(Comm.ExecuteScalar());
}
finally
{
Conn.Close();
Conn.Dispose();
}
return data;
}
private string ParseData(string data)
{
return data.Replace(";", "','");
}
Haven't tried it, but hope you get the idea. Either way, please for your own sake, do some research on what is the best way to handle sql connections in c# and also how to prevent SQL injections.

Getting data from each row in a SQL Server CE database

I have done this before, but for the life of me I can't remember how this worked.
I have a database that has a bunch of rows with data in them like names and ID numbers. What I need to do is populate a treeview from names in the database. I am running up against an issue just getting the reader to read multiple rows in the database. It only seems to be reading the first row and not subsequent rows. the actual task would be similar to below :
For each row in database add a parent node to treeview where the name is = to (reader[4].ToString()). That's about it. At the moment all I am trying to do is just get it to pop a messagebox showing that it's reading the multiple rows.
Please what am I missing to get this working?
SqlCeConnection conn = null;
try
{
using (conn = new SqlCeConnection("Data Source =" + ConfigurationFile + "; Password =*********"))
{
conn.Open();
SqlCeCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from t_mainprofiles";
cmd.ExecuteNonQuery();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
ID = (Convert.ToInt32(reader[1]));
profileID = (Convert.ToInt32(reader[2]));
profileNAME = (reader[4].ToString().Trim());
profileLOC = (reader[5].ToString().Trim());
profileCHILD = (reader[6].ToString().Trim());
}
MessageBox.Show(profileNAME);
reader.Close();
}
}
catch(Exception error)
{
MessageBox.Show(""+error);
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
finally
{
conn.Close();
}
Try removing the line cmd.ExecuteNonQuery();
Here is an example from MSDN
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.read(v=vs.110).aspx

Error "There is already an open DataReader associated with this Command which must be closed first" when using 2 distinct commands

I have this legacy code :
private void conecta()
{
if (conexao.State == ConnectionState.Closed)
conexao.Open();
}
public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{
List<string[]> historicos = new List<string[]>();
conecta();
sql =
#"SELECT *
FROM historico_verificacao_email
WHERE nm_email = '" + email + #"'
ORDER BY dt_verificacao_email DESC, hr_verificacao_email DESC";
com = new SqlCommand(sql, conexao);
SqlDataReader dr = com.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();
sql =
#"SELECT COUNT(e.cd_historico_verificacao_email) QT
FROM emails_lidos e
WHERE e.cd_historico_verificacao_email =
'" + dr["cd_historico_verificacao_email"].ToString() + "'";
tipo_sql = "seleção";
conecta();
com2 = new SqlCommand(sql, conexao);
SqlDataReader dr3 = com2.ExecuteReader();
while (dr3.Read())
{
//quantidade de emails lidos naquela verificação
dados_historico[4] = dr3["QT"].ToString();
}
dr3.Close();
conexao.Close();
//login
dados_historico[5] = dr["cd_login_usuario"].ToString();
historicos.Add(dados_historico);
}
dr.Close();
}
else
{
dr.Close();
}
conexao.Close();
return historicos;
}
I have created two separates commands to correct the issue, but it still continues: "There is already an open DataReader associated with this Command which must be closed first".
An additional info: the same code is working in another app.
Just add the following in your connection string:
MultipleActiveResultSets=True;
The optimal solution could be to try to transform your solution into a form where you don't need to have two readers open at a time. Ideally it could be a single query. I don't have time to do that now.
If your problem is so special that you really need to have more readers open simultaneously, and your requirements allow not older than SQL Server 2005 DB backend, then the magic word is MARS (Multiple Active Result Sets). http://msdn.microsoft.com/en-us/library/ms345109%28v=SQL.90%29.aspx. Bob Vale's linked topic's solution shows how to enable it: specify MultipleActiveResultSets=true in your connection string. I just tell this as an interesting possibility, but you should rather transform your solution.
in order to avoid the mentioned SQL injection possibility, set the parameters to the SQLCommand itself instead of embedding them into the query string. The query string should only contain the references to the parameters what you pass into the SqlCommand.
You can get such a problem when you are two different commands on same connection - especially calling the second command in a loop. That is calling the second command for each record returned from the first command. If there are some 10,000 records returned by the first command, this issue will be more likely.
I used to avoid such a scenario by making it as a single command.. The first command returns all the required data and load it into a DataTable.
Note: MARS may be a solution - but it can be risky and many people dislike it.
Reference
What does "A severe error occurred on the current command. The results, if any, should be discarded." SQL Azure error mean?
Linq-To-Sql and MARS woes - A severe error occurred on the current command. The results, if any, should be discarded
Complex GROUP BY on DataTable
I suggest creating an additional connection for the second command, would solve it. Try to combine both queries in one query. Create a subquery for the count.
while (dr3.Read())
{
dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}
Why override the same value again and again?
if (dr3.Read())
{
dados_historico[4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}
Would be enough.
I bet the problem is being shown in this line
SqlDataReader dr3 = com2.ExecuteReader();
I suggest that you execute the first reader and do a dr.Close(); and the iterate historicos, with another loop, performing the com2.ExecuteReader().
public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{
List<string[]> historicos = new List<string[]>();
conecta();
sql = "SELECT * FROM historico_verificacao_email WHERE nm_email = '" + email + "' ORDER BY dt_verificacao_email DESC, hr_verificacao_email DESC";
com = new SqlCommand(sql, conexao);
SqlDataReader dr = com.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
//System.Windows.Forms.MessageBox.Show(dados_historico[1]);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();
dados_historico[5] = dr["cd_login_usuario"].ToString();
historicos.Add(dados_historico);
}
dr.Close();
sql = "SELECT COUNT(e.cd_historico_verificacao_email) QT FROM emails_lidos e WHERE e.cd_historico_verificacao_email = '" + dr["cd_historico_verificacao_email"].ToString() + "'";
tipo_sql = "seleção";
com2 = new SqlCommand(sql, conexao);
for(int i = 0 ; i < historicos.Count() ; i++)
{
SqlDataReader dr3 = com2.ExecuteReader();
while (dr3.Read())
{
historicos[i][4] = dr3["QT"].ToString(); //quantidade de emails lidos naquela verificação
}
dr3.Close();
}
}
return historicos;
Add MultipleActiveResultSets=true to the provider part of your connection string. See the example below:
<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
Try to combine the query, it will run much faster than executing an additional query per row.
Ik don't like the string[] you're using, i would create a class for holding the information.
public List<string[]> get_dados_historico_verificacao_email_WEB(string email)
{
List<string[]> historicos = new List<string[]>();
using (SqlConnection conexao = new SqlConnection("ConnectionString"))
{
string sql =
#"SELECT *,
( SELECT COUNT(e.cd_historico_verificacao_email)
FROM emails_lidos e
WHERE e.cd_historico_verificacao_email = a.nm_email ) QT
FROM historico_verificacao_email a
WHERE nm_email = #email
ORDER BY dt_verificacao_email DESC,
hr_verificacao_email DESC";
using (SqlCommand com = new SqlCommand(sql, conexao))
{
com.Parameters.Add("email", SqlDbType.VarChar).Value = email;
SqlDataReader dr = com.ExecuteReader();
while (dr.Read())
{
string[] dados_historico = new string[6];
dados_historico[0] = dr["nm_email"].ToString();
dados_historico[1] = dr["dt_verificacao_email"].ToString();
dados_historico[1] = dados_historico[1].Substring(0, 10);
//System.Windows.Forms.MessageBox.Show(dados_historico[1]);
dados_historico[2] = dr["hr_verificacao_email"].ToString();
dados_historico[3] = dr["ds_tipo_verificacao"].ToString();
dados_historico[4] = dr["QT"].ToString();
dados_historico[5] = dr["cd_login_usuario"].ToString();
historicos.Add(dados_historico);
}
}
}
return historicos;
}
Untested, but maybee gives some idea.

get the protein that contains specific sequence using OLEDB

Here is a background on my program: each protein is made from a sequence of amino acids(or AA)
I have some tables :tblProInfo(that contains general info about proteins),tblOrderAA(that contains the sequence(AA sequence) of specific protein(for each protein there is a serial number that i set before))
now, I'm trying to retvive the science names of the protein that contains part of sequence that the user put in textbox1. It is likely that more than one protein contains the sequence that the user typed.
Here is my code. I got "Syntax error" and I'm sure I have more mistakes.Please HELP me!
public void OpenDB()
{
dataConnection = new OleDbConnection();
try
{
dataConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Projects_2012\\Project_Noam\\Access\\myProject.accdb";
dataConnection.Open();
}
catch (Exception e)
{
MessageBox.Show("Error accessing the database: " +
e.Message,
"Errors",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private string FromCodonsToProtein(string codons)
{
OpenDB();
int sizePro=0, i,counter=0,serialPro;
string st="",tempst="";
OleDbCommand datacommand = new OleDbCommand();
datacommand.Connection = dataConnection;
datacommand.CommandText = "SELECT tblProInfo.proInfoAAnum, tblProInfo.proInfoSerialNum,tblProInfo.proInfoScienceName FROM tblProInfo";
OleDbDataReader dataReader = datacommand.ExecuteReader();
while(dataReader.Read())
{
sizePro = dataReader.GetInt32(counter);
serialPro= dataReader.GetInt32(counter+1);
counter++;
OleDbCommand cmd= new OleDbCommand();
cmd.Connection = dataConnection;
cmd.CommandText = "SELECT tblOrderAA.orderAACodon1 FROM tblOrderAA"
+"WHERE (((tblOrderAA.orderAASerialPro)='"+serialPro+"'))";
OleDbDataReader rdr = cmd.ExecuteReader();
tempst="";
for (i = 0; i > sizePro; i++)
{
tempst = tempst + rdr.GetString(i);
}
if (tempst.Contains(codons))
{
st = st + " \n" + dataReader.GetString(counter);
}
}
return st;
}
Missing a space here
cmd.CommandText = "SELECT tblOrderAA.orderAACodon1 FROM tblOrderAA"
+"WHERE (((tblOrderAA.orderAASerialPro)='"+serialPro+"'))";
rewrite in this way
cmd.CommandText = "SELECT tblOrderAA.orderAACodon1 FROM tblOrderAA"
+" WHERE (((tblOrderAA.orderAASerialPro)='"+serialPro+"'))";
// ^ here
However you should use parametrized query (also with msaccess) to avoid possible errors and injection attacks.
Another problem is the global dataConnection. Don't do that, you gain nothing in this way.
Return the connection and encapsulate it with a using statement.
For example:
public OleDbConnection OpenDB()
{
dataConnection = new OleDbConnection();
dataConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Projects_2012\\Project_Noam\\Access\\myProject.accdb";
dataConnection.Open();
return dataConnection;
}
then in the calling code use this syntax
using(OleDbConnection cnn = OpenDB())
{
// in the rest of your code, replace dataConnection with cnn
// The using statement will ensure that in the case of exceptions
// your connection will be allways closed and properly disposed
........
}
EDIT: Can't give you a full working solutions, too many aspects of your problem are unknown to me, however a great simplification will be to change your query in this way
SELECT DISTINCT
tblProInfo.proInfoAAnum,
tblProInfo.proInfoSerialNum,
tblProInfo.proInfoScienceName
FROM tblProInfo LEFT JOIN tblOrderAA
ON tblOrderAA.orderAASerialPro = tblProInfo.proInfoSerialNum
WHERE tblOrderAA.orderAACodon1 = #codons
Try it directly in access using its query editor, if it works as you expected then change your code. You don't need two query and crossed loops to get the results.

C# Foreach with MySQL

I am currently working on a patching system in C# and I have came across a small complication. I am using MySQL to store an archive for my update list. The patching system then detects the version of program, and downloads every patch after that version. Though I just started learning how to use MySQL in C# so i'm not sure how to do, or call a lot of the functions needed. What I want to do is use foreach to call all values in the "version" column/row, then use a while loop to check against current version and new version until they are the same. I just cant seem to figure out how to use the two together and can't find any references.
using (SqlCon = new MySqlConnection(connString))
{
SqlCon.Open();
string command = "SELECT * FROM version ORDER BY version";
MySqlCommand GetLatestVersion = new MySqlCommand(command, SqlCon);
using (MySqlDataReader DR = GetLatestVersion.ExecuteReader())
{
while (DR.Read())
{
foreach(DataTable i in DR)
{
while(v1 < v2)
{
string LatestVersion = Convert.ToString(DR.GetValue(1));
string WebURL = Convert.ToString(DR.GetValue(2));
update.DownloadProgressChanged += new DownloadProgressChangedEventHandler(download);
update.DownloadFileCompleted += new AsyncCompletedEventHandler(extration);
update.DownloadFileAsync(new Uri(WebURL), tempFilePath + "patch" + Latest_Version + ".zip");
}
}
}
}
}
SqlCon.Close();
I would greatly appreciate any help.
just remove the inner foreach and you are good to go.
First thing is you don't need the SqlCon.Close(); at the end. At the end of the using block, the object is disposed of (the point of a using block).
You can modify your select statement to only select versions greater than your program's current version. This way, any records selected should be processed/downloaded. (I put the version in quotes in the SQL statement below because your code indicates that it's a string. You're probably better off specifying this value as numeric for sorting/comparison purposes, though.)
//for readability, I changed the variable name to myProgramsVersion
using (SqlCon = new MySqlConnection(connString))
{
SqlCon.Open();
string command = "SELECT * FROM version where version > '" + myProgramsVersion + "' ORDER BY version";
MySqlCommand GetLatestVersion = new MySqlCommand(command, SqlCon);
using (MySqlDataReader DR = GetLatestVersion.ExecuteReader())
{
while (DR.Read())
{
string LatestVersion = Convert.ToString(DR.GetValue(1));
string WebURL = Convert.ToString(DR.GetValue(2));
update.DownloadProgressChanged += new DownloadProgressChangedEventHandler(download);
update.DownloadFileCompleted += new AsyncCompletedEventHandler(extration);
update.DownloadFileAsync(new Uri(WebURL), tempFilePath + "patch" + Latest_Version + ".zip");
}
}
}

Categories

Resources