I have a C# form that have a 6 filters (5 combobox, and 1 textbox) that the user can use to perform a search. The problem is that the user can leave some as blank or to use it all. To have a filtered search I used AND when doing a SELECT query, but the problem is it will return a blank or empty search when some of the filters is/are blank. If I will make each condition a query, I will have around 700 and so query. So I have search the closet, I think, scenario in this link
Ignore empty textboxes while searching in database
using (SqlConnection conn = new SqlConnection(#"Data Source=(local);
Initial Catalog=inventory;
Integrated Security=True"))
{
conn.Open();
string query = "SELECT * FROM [dbo].[product] WHERE IsDeleted = '0'";
using (SqlCommand scmd = new SqlCommand())
{
if (!string.IsNullOrEmpty(cmbItem.Text))
{
query += " AND Item Like #Item";
scmd.Parameters.Add("#Item", SqlDbType.VarChar).Value = "%" + item + "%";
}
}
if (!string.IsNullOrEmpty(cmbBrand.Text))
{
query += " AND Brand Like #Brand";
scmd.Parameters.Add("#Brand", SqlDbType.VarChar).Value = "%" + brand + "%";
}
//...additional query
}
scmd.CommandText = query;
scmd.Connection = conn;
using (SqlDataAdapter sda = new SqlDataAdapter(scmd))
{
dataGridView1.Refresh();
DataTable dt = new DataTable();
sda.Fill(dt);
dataGridView1.DataSource = dt;
}
conn.Close();
}
And when performing the search, it is having an error like this;
'Invalid column name 'IsNull'.'
My original query goes something like this. But this will select nothing if one of the where condition is blank/empty.
SELECT * FROM [dbo].[product] WHERE Item = '" + item + "'
AND Brand = '" + brand + "'
AND Description = '" +desc + "'
AND Manufacturer = '" + manu + "'
AND Car = '" + car + "'
AND Year = '" + year + "'
If I use OR instead of AND. It will select something like this.
OR Statement
OR Statement
Below are the images for an ideal search.
Image for ideal selection
Image for ideal selection
Solved, by changing IsDeleted='0' to 1=1
string query = #"SELECT * FROM[dbo].[product] WHERE 1=1";
you can use store procedure and set parameter to default value
sample:
create proc sptest
#Fname nvarchar(50),
#Lname nvarchar(50),
#NCode nvarchar(12),
#UserType int
as
SELECT DISTINCT PersonID,
FName,
LName,
NationalID,
UserType
FROM Persons
WHERE
(FName LIKE('%' + #Fname + '%') OR (#Fname = ''))
AND (LName LIKE('%' + #Lname + '%') OR (#Lname = ''))
AND ((NCode = #NCode) OR (#NCode = ''))
AND ((UserType = #UserType) OR (#UserType = 0))
when textbox is empty or dropdownlists not is selected, get all record
Your original if/and conditions should work, but what you might be running into is a false resolution of the table COLUMN vs the PARAMETER. Since you have the example of
Item like #Item
if there is no actual parameter Item, SQL is implying to use its own value. For these types of queries, I try to prefix the parameter name to match. Change to
Item like #parmItem
and obviously change your parameter name string to match the "#parmItem" reference. This way there is no ambiguity in what value the SQL engine is looking for.
Related
I want to select rows from my SQL Server table (it has 3 columns) and to display them into my Datagridview. My problem about null values. How can I pass null values? (Sometimes the first column and the second column are empty.
).
Below is my code:
string cm = "SELECT column1, column2, column3 FROM mytablename WHERE column1='"
+ sIS[mSI] + "' AND column2='" + sR[mSSI] + "' OR column1='" + sR[mSSI]
+ "' AND column2='" + sIS[mSI] + "'";
Note: I edited my code.
You should be using parameters to pass values into a SQL statement or else you will be vulnerable to SQL injection attacks. You can create a SqlCommand object, create SqlParameter objects, then set values on them. If any of your values are null, then you can pass DBNull.Value as the parameter value.
SqlCommand cmd = con.CreateCommand();
string cm = "SELECT column1, column2, column3 "
cm += "FROM mytablename "
cm += "WHERE column1=#mSI "
cm += "AND column2=#mSSI OR column1=#mYSI AND column2=#mSI";
cmd.CommandText = cm;
for(int mSSI=0; mSSI<sR.Count(); mSSI++)
{
cmd.Parameters.AddWithValue("#mSI ", sR[mSI]);
// check for a null value
if (sr[mSSI] == null)
{
cmd.Parameters.AddWithValue("#mSSI", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#mSSI", sR[mSSI]);
}
cmd.Parameters.AddWithValue("#mYSI", sR[mYSI]);
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dat = new DataTable();
sd.Fill(dat);
// clear parameters after each iteration
cmd.Parameters.Clear()
}
I think the answer to your question is using "DBNull.Value" as mentioned above, something like this;
string cm = "SELECT column1, column2, column3 FROM mytablename WHERE column1='"
+ DBNull.Value + "' AND column2='" + DBNull.Value + "' OR column1='" + sR[mSSI]
+ "' AND column2='" + DBNull.Value + "'";
I'm making a class reservation website and having trouble with creating the button.
I would like to customer to insert two details session into two textboxes, session type "class" or "workshop" and date & time and they will be able to see that information from the DataGridView displayed.
Once they hit the "Reserve" button the button will run a query where it'll add the chosen session from Session table to Reservation table. However my code executes with no errors but does not update the "Reservation" table.
here's my code:
OleDbConnection myConnection = GetConnection();
OleDbCommand cmd = myConnection.CreateCommand();
string query = "select COUNT(*) from [Yoga-Session] where [session type] = '" + txt_type.Text + "' and duration = '" + txt_datetime.Text + "';";
OleDbCommand command = new OleDbCommand(query, myConnection);
myConnection.Open();
int rows1 = (Int32)command.ExecuteScalar();
if (rows1 >= 1)
{
cmd = new OleDbCommand("Select session_id from [yoga-session] where [session type] = '" + txt_type.Text + "' and duration = '" + txt_datetime.Text +"';",myConnection);
int classId = (Int32)command.ExecuteScalar();
cmd = new OleDbCommand("select client_id from client where name = '" + Session["[name]"] + "';", myConnection);
int clientID = (Int32)command.ExecuteScalar();
string query1 = "insert into reservation (session_id, client_id, client_name) values ('" + classId + "','" + clientID + "','" + Session["[name]"].ToString() + "');";
cmd = new OleDbCommand(query1, myConnection);
cmd.ExecuteNonQuery();
Response.Write("Reservation successful");
Response.Redirect("reservation.aspx");
myConnection.Close();
}
}
}
int classId = (Int32)cmd.ExecuteNonQuery();
int clientID = (Int32)cmd.ExecuteNonQuery();
You need to use cmd.ExecuteScalar() to get session_id and client_id values. ExecuteNonQuery returns you no of rows affected by the SQL query.
Also see what #Sherantha pointed out.
ExecuteNonQuery() is not for SELECT commands. To get a field value from SELECT command we need to use ExecuteScalar().
Try replacing;
int rows1 = (Int32)command.ExecuteScalar();
Just a small headsup before I compose my real answer (because I don't have rep to comment)
Firstly: Use Prepared Statements. They help immensely in reducing errors from typing SQL queries, as well as a way to prevent SQL Injection Attacks in real-world situations.
Secondly: While not really needed in most database types, it is recommended that a naming convention is strictly uniform in your code.
Well aside from that, I will get to the real answer now.
Looking at the code, I am assuming that classID and clientID are integers, but in your code, it looks like they are parsed as strings due to the ' ' characters. Do not use the characters when inserting integers.
EDIT: is [session type] meant to be [session_type]?
You should use query1 instead of query.
string query1 = "insert into reservation (session_id, client_id, client_name) values ('" + classId + "','" + clientID + "','" + Session["[name]"].ToString() + "');";
cmd = new OleDbCommand(query1, myConnection);// not query but query1
cmd.ExecuteNonQuery();
Response.Write("Reservation successful");
PS: Use sql data reader to select data.
cmd = new OleDbCommand("Select session_id from [yoga-session] where [session type] = '" + txt_type.Text + "' and duration = '" + txt_datetime.Text +"';",myConnection);
SqlDataReader rdr = cmd.ExecuteReader();
int classId = 0;
while (rdr.Read())
{
clientID = Convert.ToInt32(rdr["session_id"]);
}
string connetionString = null;
SqlConnection connection;
SqlCommand command;
SqlDataAdapter adpter = new SqlDataAdapter();
DataSet ds = new DataSet();
XmlReader xmlFile;
string sql = null;
int ID = 0;
string Name = null, Text = null, Screenname = null;
connetionString = "myconnection";
connection = new SqlConnection(connetionString);
xmlFile = XmlReader.Create("my.XML", new XmlReaderSettings());
ds.ReadXml(xmlFile);
int i = 0;
connection.Open();
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
ID = Convert.ToInt32(ds.Tables[0].Rows[i].ItemArray[0]);
Text = ds.Tables[0].Rows[i].ItemArray[1].ToString().Replace("'", "''");
Name = ds.Tables[0].Rows[i].ItemArray[2].ToString().Replace("'", "''");
Screenname = ds.Tables[0].Rows[i].ItemArray[3].ToString().Replace("'", "''");
//sql = "insert into nicktest values(" + ID + ",'" + Text + "'," + Name + "," + Screenname + "," + DateTime.Now.ToString() + ")";
sql = "If Exists(Select * from niktest2 Where Id = ID) " +
" BEGIN " +
" update niktest2 set Name = '" + Text + "' , Screenname = '" + Name + "', Profimg= '" + Screenname + "', InsertDateTime= '" + DateTime.Now.ToString() + "' where Id=ID" +
" END " +
" ELSE " +
" BEGIN " +
" insert into niktest2(Id,Name,Screenname,Profimg,InsertDateTime) values('" + ID + "','" + Text + "','" + Name + "','" + Screenname + "' ,'" + DateTime.Now.ToString() + "')" +
" END ";
command = new SqlCommand(sql, connection);
adpter.InsertCommand = command;
adpter.InsertCommand.ExecuteNonQuery();
}
}
after running this code only first row gets updated even my xml file is having more data.
i Want to insert all data into database with assign id to it in xml file.
Please help..
As soon as you have inserted one row, this condition will be true:
If Exists(Select * from niktest2 Where Id = ID)
So you will perform the update, rather than the insert, so you will only ever get one row in the database.
Since you are using SQL Server 2008 I would adopt a completely different approach, using Parameterised queries, MERGE, and table valued parameters.
The first step would be to create your table valued parameter (I have had to guess at your type:
CREATE TYPE dbo.nicktestTableType AS TABLE
(
Id INT,
Name VARCHAR(255),
Screenname VARCHAR(255),
Profimg VARCHAR(255)
);
Then you can write your MERGE statement to upsert to the database:
MERGE nicktest WITH (HOLDLOCK) AS t
USING #NickTestType AS s
ON s.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET Name = s.Name,
Screenname = s.Screenname,
Profimg = s.Profimg,
InsertDateTime = GETDATE()
WHEN NOT MATCHED THEN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (s.Id, s.Name, s.Screenname, s.Profimg, GETDATE());
Then you can pass your datatable to the query as a parameter:
using (var command = new SqlCommand(sql, connection))
{
var parameter = new SqlParameter("#NickTestType", SqlDbType.Structured);
parameter.Value = ds.Tables[0];
parameter.TypeName = "dbo.nicktestTableType";
command.Parameters.Add(parameter);
command.ExecuteNonQuery();
}
If you don't want to make such a drastic change, then you should at the very least use parameterised queries, so your SQL would be:
IF EXISTS (SELECT 1 FROM nicktest WHERE ID = #ID)
BEGIN
UPDATE nicktest
SET Name = #Name,
ScreenName = #ScreeName,
InsertDateTime = GETDATE()
WHERE ID = #ID;
END
ELSE
BEGIN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (#ID, #Name, #Screenname, #Profimg, GETDATE());
END
Or preferably still using MERGE as the HOLDLOCK table hint prevents (or at least massively reduces the chance of) a race condition:
MERGE nicktest WITH (HOLDLOCK) AS t
USING (VALUES (#ID, #Name, #ScreenName, #ProfImg)) AS s (ID, Name, ScreenName, ProfImg)
ON s.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET Name = s.Name,
Screenname = s.Screenname,
Profimg = s.Profimg,
InsertDateTime = GETDATE()
WHEN NOT MATCHED THEN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (s.Id, s.Name, s.Screenname, s.Profimg, GETDATE());
This will be considerably less efficient than the first solution though using table-valued parameter
Then your c# would be something like:
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#ID", ds.Tables[0].Rows[i][0]);
command.Parameters.AddWithValue("#Name", ds.Tables[0].Rows[i][1]);
command.Parameters.AddWithValue("#ScreeName", ds.Tables[0].Rows[i][2]);
command.Parameters.AddWithValue("#ProfImg", ds.Tables[0].Rows[i][3]);
command.ExecuteNonQuery();
}
}
Im using this code
updt = new SqlCommand("update dailysale set totalunit1 = totalunit1 - " + double.Parse(textBox3.Text) +" where material = '" + comboBox4.SelectedItem.ToString() +"' AND sn > '" + enmbr + "' ", agr, transac);
but this doesn't make update whereas
SqlCommand up2 = new SqlCommand("update dailysale set sn = sn +2 where sn > '" + enmbr + "' ", agr,transac);
is working for me
Using a parameterized query avoid subtle syntax errors hidden in the string concatenation and prevent any possibility of Sql Injections
string cmdText = "update dailysale set totalunit1 = totalunit1 - #sold " +
"where material = #mat AND sn > #emb";
updt = new SqlCommand(cmdText, agr);
updt.Transaction = transac;
updt.Parameters.AddWithValue("#sold", Convert.ToDouble(textbox1.Text));
updt.Parameters.AddWithValue("#mat", comboBox4.SelectedItem.ToString());
updt.Parameters.AddWithValue("#emb", embr);
int rowsUpdated = updt.ExecuteNonQuery();
if(rowsUpdated > 0)
MessageBox.Show("Record updated!");
In your original text you miss the double quotes before the AND and probably the conversion of your textbox to a double introduces a decimal separator not understood by your database. Instead a parameterized query leaves the work to correctly quote the values to the framework code and your query text is no more obscured by the string concatenations and quoting
Did you check the result count?
if updt.ExecuteNonQuery() <> 0 Then
If it's zero then your where clause didn't select any records
If it's not zero then maybe you didn't commit your transaction.
transact.Commit()
I use mysql as database where I store my data.
I have a windows form with textboxes radiobuttons, comboboxes and more; where people give personal information about themselves like (first name, last name, sex, date birthday, phone, father name and more like this). (40 fields total)
I want to do a search button. With this button I want to fill some fields and after I push the search button a new window be opened containing all people with same personal information. I achieved to do a search button for one field (for example searching only by name).
But I have a problem when I select to search with more than one fields. For example I select to search all people who have name:Chris, Nickname:Dung, sex:Male, Birth_Country:UK and other but when I push search it gives back a window with irrelevant with the search data. Can someone help me with that?
The code I made for the search button after changes is:
public MySqlDataAdapter da;
public DataSet ds;
public string sTable = "data";
private void anazitisi_button_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
try
{
conn = openconnectio.GetConn();
string radiob = null;
if (radioButton1.Checked == true)
{
radiob = radioButton1.Text;
}
else if(radioButton2.Checked == true)
{
radiob = radioButton2.Text;
}
StringBuilder Query = new StringBuilder("SELECT * FROM data d INNER JOIN country c ON d.id_data = c.id_country WHERE 1=1 ");
if (!String.IsNullOrEmpty(textBox1.Text))
Query.Append(" AND name like '" + textBox1.Text + "'");
if (!String.IsNullOrEmpty(textBox2.Text))
Query.Append(" AND lastname like '" + textBox2.Text + "'");
if (!String.IsNullOrEmpty(radiob))
Query.Append(" AND sex like '" + radiob + "'");
if (!String.IsNullOrEmpty(maskedTextBox1.Text))
Query.Append(" AND birthdate like '" + maskedTextBox1.Text + "'");
if (!String.IsNullOrEmpty(maskedTextBox2.Text))
Query.Append(" AND phone_number like '" + maskedTextBox2.Text + "'");
MySqlDataAdapter da = new MySqlDataAdapter(Query.ToString(), conn);
ds = new DataSet();
da.Fill(ds, sTable);
conn.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
DataGridView dg1 = new DataGridView();
form2.Controls.Add(dg1);
dg1.Dock = DockStyle.Fill;
dg1.Refresh();
dg1.DataSource = ds;
dg1.DataMember = sTable;
form2.Show();
if (conn != null)
{
conn.Close();
}
}
}
My results after search is fine when i comment that code:
(birthdate code) and i dont used as search of course.
//if (!String.IsNullOrEmpty(maskedTextBox1.Text))
// Query.Append(" AND birthdate like '" + maskedTextBox1.Text + "'");
But when i use the (birthdate code) i get us result only a blank row.
I think because the birthdate maskedTextbox have a mask: 00/00/0000
Any suggestion?
Thanks.
I think you should consider three things
1- You may replace OR with And in your query
I mean instead of using
da = new MySqlDataAdapter(
"SELECT * FROM data INNER JOIN country ON id_data = id_country
WHERE name like '" + textBox1.Text +
"'OR lastname like '" + textBox2.Text +
"'OR sex like '" + radiob +
"'OR birthdate like '" + maskedTextBox1.Text +
"'OR phone
_number like '" + maskedTextBox2.Text + "' ;", conn);
You may use
da = new MySqlDataAdapter(
"SELECT * FROM data INNER JOIN country ON id_data = id_country
WHERE name like '" + textBox1.Text +
"'AND lastname like '" + textBox2.Text +
"'AND sex like '" + radiob +
"'AND birthdate like '" + maskedTextBox1.Text +
"'AND phone_number like '" + maskedTextBox2.Text + "' ;", conn);
2- You have to build your query string based on your text boxes and else seeing if they have any value, something like this:
StringBuilder Query = "SELECT * FROM data INNER JOIN country ON id_data = id_country
WHERE 1=1 ";
if(!String.IsNullOrEmpty(textBox1.Text))
Query.Append(" AND name like '" + textBox1.Text);
....
3- Sql Injection vulnerabilities
oh my God !!! Some programming !!!
where clause must created by and/or ,... other clauses ,
so ,
two solutions exist :
On server Side by Store Procedure by below definition :
you must care by position of AND/OR in below :
CREATE PROCEDURE [dbo].[dbo_Bank_SELByFields]
(
#ID nvarchar(50) = NULL ,
#BankName nvarchar(50) = NULL ,
#BankCode nvarchar(50) = NULL ,
#Address nvarchar(50) = NULL ,
#BranchCode nvarchar(50) = NULL
)
AS
SELECT * FROM dbo.Bank WHERE
(
(#ID IS NULL OR ID = #ID) AND
(#BankName IS NULL OR BankName =#BankName) AND
(#BankCode IS NULL OR BankCode =#BankCode) AND
(#Address IS NULL OR Address =#Address) AND
(#BranchCode IS NULL OR BranchCode =#BranchCode)
) ORDER BY BankCode
//---you know call the Sp . OK?
and other solution in your business layer code :
if you use ORM such as Entity Framework , very easy By IQueryable object, you can use below :
var selectByEnyCondition=(from c in ctx.customer ...);
//---- you must add by below way :
if(!(String.IsNullOrEmpty(txtName.Text)))
{
selectByEnyCondition.Where(.....);
}
if(!String.IsNullOrEmpty(sex))
{
selectByEnyCondition= opportunites.Where(.....);
}
//------
/* **** beacuse you use by ADO.NET technique you should use StringBuilder -->*/
StringBuilder query;
query.add("SELECT * FROM BankTbl WHERE ");
if(!(String.IsNullOrEmpty(txtName.Text))){
query.Add("Name Like {0}",txtName.Text);
//-----now continue for build your criteria
king reguard
bye.....