sql like query does not work - c#

I am trying to retrieve video name from my database where the subject of the video is like my subject to search.
I try the like query but it was not return values.
Can you kindly give the suggestions.
I am using c# with sql server.
Here is my code.
if (con.State == ConnectionState.Open)
con.Close();
con.Open();
string s1 = textBox1.Text;
cmd = new SqlCommand("select Video_Name,subject from Videos where subject like '%"+ s1 +" % ' " ,con);
//cmd = new SqlCommand("select Video_Name from Videos where subject='"+ s1+"' ", con);
SqlDataReader dr = cmd.ExecuteReader();
ArrayList a = new ArrayList();
label2.Visible = true;
label3.Visible = true;
//if (dr.Read())
{
while (dr.Read())
{
a.Add(dr[0].ToString());
}
foreach (string n in a)
{
comboBox1.Items.Add(n);
}
MessageBox.Show("Search succeded");
}

Use a parameterized query
string s1 = textBox1.Text;
cmd = new SqlCommand("select Video_Name,subject from Videos where subject like #video",con);
cmd.Parameters.AddWithValue("#video", "%" + s1 + "%");
In this way you avoid the Sql Injection problem and your command text is more readable.
This will help also in formatting your command text without subtle typing errors and without the need to add quotes around strings. With a parameter, the burden to correctly quoting the parameter value is passed to the framework code that knows better how to do it correctly.
By the way, you could avoid the second loop setting the combobox.Datasource property to the ArrayList variable a
comboBox1.Datasource = a;

Maybe it is because you have a space after the last % and its '
"select Video_Name,subject from Videos where subject like '%"+ s1 +">> % ' "<<
try something like this
"select Video_Name,subject from Videos where subject like '%"+s1+"%'"

cmd = new SqlCommand("select Video_Name,subject from Videos where subject like #vdnam",con);
cmd.Parameters.AddWithValue("#vdnam", "%" + VdName + "%");
if (dr.HasRows)
{
while (dr.Read())
{
a.Add(dr[0].ToString());
}
comboBox1.Datasource= a.List();
MessageBox.Show("Search succeded");
}

Steve's answer is of course right.
The main problem is here, your query parameter is inside single quotes. In quotes, SQL will recognize it as a string literal and never sees it as a parameter.

Related

Show data in Textboxes from database in C#

Is there anything wrong with my code? It is not showing data in textboxes. The same funtion is working for another table in database but not for this one.
private void metroButton1_Click(object sender, EventArgs e)
{
con = new SqlConnection(constr);
String query = "Select FROM Student WHERE Std_ID = '" + metroTextBox1.Text + "'";
cmd = new SqlCommand(query, con);
con.Open();
try
{
using (SqlDataReader read = cmd.ExecuteReader())
{
while (read.Read())
{
// metroTextBox1.Text = (read["ID"].ToString());
metroTextBox2.Text = (read["Name"].ToString());
metroTextBox3.Text = (read["F_Name"].ToString());
metroTextBox4.Text = (read["Std_Age"].ToString());
metroTextBox5.Text = (read["Address"].ToString());
metroTextBox6.Text = (read["Program"].ToString());
metroComboBox1.Text = (read["Course"].ToString());
}
}
}
finally
{
con.Close();
}
}
you need to give column names in the select statement or select *
for example :
String query = "Select * from Student WHERE Std_ID = '" + metroTextBox1.Text + "'";
Not related to Question: you can change the while loop to if condition if you have one record for given id. even there are many records for given id you will see the last record data only because of the while loop will overwrite the textboxes in every record.
Update :
There isn't anything wrong with Syntax because the same syntax is
working for modifying teacher funtion.
No, this is incorrect, remove the try catch in your code then you will see the exception of syntax error

How to pass a C# variable with apostrophe through MySql

I'm having a problem inputting variables into my database. I've seen other posts on how to pass a variable through by just escaping it, but those solutions do not apply because I am getting my variable's through an API. I'm cycling though data with a foreach loop by the way.
level = "" + x.Account_Level + "";
name = "" + x.name + "";
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(" + level + ", " + name + ")";
command.ExecuteNonQuery();
Sometimes, a variable will come back with an apostrophe and will screw up the code. Is it possible to insert a slash before every apostrophe or is there a way like in PHP to just push the whole variable through with single quotes? Thanks!
Edit:
Would this work? I think I need to add the i to change the name of the parameter each loop, due to it claiming the parameter as already declared.
using (var web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
var jsonString = responseFromServer;
var jss = new JavaScriptSerializer();
var MatchesList = jss.Deserialize<List<Matches>>(jsonString);
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
MySqlConnection connect = new MySqlConnection(connectString);
MySqlCommand command = connect.CreateCommand();
int i = 1;
connect.Open();
foreach (Matches x in MatchesList)
{
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(?level" + i + ", ?name" + i + ")";
command.Parameters.AddWithValue("level" + i, x.Account_Level);
command.Parameters.AddWithValue("mode" + i, x.name);
command.ExecuteNonQuery();
i++;
}
connect.Close();
}
The quick and dirty fix is to use something like:
level = level.Replace("'","whatever");
but there are still problems with that. It won't catch other bad characters and it probably won't even work for edge cases on the apostrophe.
The best solution is to not construct queries that way. Instead, learn how to use parameterised queries so that SQL injection attacks are impossible, and the parameters work no matter what you put in them (within reason, of course).
For example (off the top of my head so may need some debugging):
MySqlCommand cmd = new MySqlCommand(
"insert into data (level, name) values (?lvl, ?nm)", con);
cmd.Parameters.Add(new MySqlParameter("lvl", level));
cmd.Parameters.Add(new MySqlParameter("nm", name));
cmd.ExecuteNonQuery();

How to get multiple rows from access database

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 { }
}

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.

SQL like statement

here i have tried to select a data from db make use of like statement, but it has search with the 1st digit of my data. but i need to write the code, like search instead of first 3 digit of my data. can any one help me.
public void CC()
{
CCddl.Items.Clear();
ListItem l = new ListItem();
l.Text = "-Select-";
CCddl.Items.Add(l);
CCddl.SelectedIndex = 0;
con.Open();
SqlCommand cmd = new SqlCommand("select Componetcode from dbo.tbl_component where Sitecode like '%" + TextBox1.Text + "%'", con);
SqlDataReader dr1;
dr1 = cmd.ExecuteReader();
while (dr1.Read())
{
ListItem n = new ListItem();
n.Text = dr1["Componetcode"].ToString().Trim();
CCddl.Items.Add(n);
}
dr1.Close();
con.Close();
}
you cannot operate the like on number you need to convert number to stirng by using cast or convert ...
EDIT
you can also make use of substring function to skip frist three char or your data in column
select * from (
select column1,cast(column2 as varchar(30)) as column2 from tablename
) d where
substring(column2,4, LEN(column2) - 3 ) like '%textosearch%'
you need to write down
select * from tablename where column like '___textosearch%'
so your code will be
SqlCommand cmd = new SqlCommand("select Componetcode from dbo.tbl_component
where Sitecode like '___" + TextBox1.Text + "%'", con);
_ allows you to match on a single character in sql , so you need to write three "_" as i done in my code
Also modify you code with sql parameter so taht it avoid SQL injection attack

Categories

Resources