I build a Web Service in ASP.Net which sends me a list of rooms.
The parameters are id's which are separated by a comma.
I saved them to a string and build a sql select query.
When I send all 4 parameters I everything works fine and I get a result. But when I send less then 4 I get an error.
System.Data.SqlClient.SqlException: Incorrect syntax near ')'.
How can I set my the parameters optional in the sql query to select just the values I entered?
Here is my code so far:
internal static List<RAUM> Raum(string RAUMKLASSE_ID, string STADT_ID, string GEBAEUDE_ID, string REGION_ID)
{
List<RAUM> strasseObject = new List<RAUM>();
string raumklasseid = RAUMKLASSE_ID;
string gebaudeid = GEBAEUDE_ID;
string stadtid = STADT_ID;
string regionid = REGION_ID;
using (SqlConnection con = new SqlConnection(#"Data Source=Localhost\SQLEXPRESS;Initial Catalog=BOOK-IT-V2;Integrated Security=true;"))
using (SqlCommand cmd = new SqlCommand(#"SELECT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID FROM RAUM r WHERE RAUMKLASSE_ID IN (" + raumklasseid + ") AND STADT_ID IN (" + stadtid + ") AND GEBAEUDE_ID IN (" + gebaudeid + ") AND REGION_ID IN (" + regionid + ")", con))
{
con.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
if (rdr["BEZEICHNUNG"] != DBNull.Value && rdr["ID"] != DBNull.Value)
{
strasseObject.Add(new RAUM()
{
RaumName = rdr["BEZEICHNUNG"].ToString(),
RaumID = rdr["ID"].ToString()
});
}
}
}
}
return strasseObject;
}
Thanks in advance for your help.
Imagine the parameter REGION_ID is an empty string. That part of your query will be something like:
...AND REGION_ID IN ()...
Because in AND REGION_ID IN (" + regionid + ")" the regionid variable will be replaced with an empty string. This is not valid SQL syntax so you'll get that exception.
Declare a function like this:
private static void AppendConstrain(StringBuilder query, string name, string value)
{
if (String.IsNullOrWhiteSpace(value))
return;
if (query.Length > 0)
query.Append(" AND ");
query.AppendFormat("{0} IN ({1})", name, value);
}
Then change your code to build the query in this way:
StringBuilder constrains = new StringBuilder();
AppendConstrain(contrains, "RAUMKLASSE_ID", RAUMKLASSE_ID);
AppendConstrain(contrains, "GEBAEUDE_ID", GEBAEUDE_ID);
AppendConstrain(contrains, "STADT_ID", STADT_ID);
AppendConstrain(contrains, "REGION_ID", REGION_ID);
StringBuilder query =
new StringBuilder("SELECT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID FROM RAUM r");
if (constrains.Length > 0)
{
query.Append(" WHERE ");
query.Append(constrains);
}
using (SqlCommand cmd = new SqlCommand(query.ToString(), con))
{
// Your code...
}
WARNING: DO NOT USE this code in production or when the input comes from the user because it's vulnerable to SQL injection. For better approaches (do not stop to the accepted answer) see Parameterize an SQL IN clause
It always be a better approach to write the stored procedures and pass the parameters. But in your approach you should split your query because of not sure the values. So, your code be something like that..
Test it yourself, i didnt check it
string raumklasseid = RAUMKLASSE_ID;
string gebaudeid = GEBAEUDE_ID;
string stadtid = STADT_ID;
string regionid = REGION_ID;
string whereClause = string.Empty;
if (!string.IsNullorEmpty(raumklasseid))
{
whereClause = "RAUMKLASSE_ID IN (" + raumklasseid + ")";
}
if (!string.IsNullorEmpty(stadtid ))
{
if(string.IsNullorEmpty(whereClause)
whereClause = "STADT_ID IN (" + stadtid + ")";
else
whereClause += "AND RSTADT_ID IN (" + stadtid + ")";
}
if (!string.IsNullorEmpty(stadtid ))
{
if(string.IsNullorEmpty(whereClause)
whereClause = "STADT_ID IN (" + stadtid + ")";
else
whereClause += "AND RSTADT_ID IN (" + stadtid + ")";
}
if (!string.IsNullorEmpty(regionid))
{
if(string.IsNullorEmpty(whereClause)
whereClause = "REGION_ID IN (" + regionid + ")";
else
whereClause += "AND REGION_ID IN (" + regionid + ")";
}
if(!string.IsNullorEmpty(whereClause)
whereClause = "WHERE " + whereClause ;
// now your cmd should be like that
using (SqlCommand cmd = new SqlCommand(#"SELECT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID FROM RAUM r " + whereClause , con))
Related
I have been searching around and I am either confusing myself or not searching for the right thing.
I have this data reader that pulls some information for a store procedure.. but I don't think I am doing it right.
string constr = ConfigurationManager.ConnectionStrings["PAYROLL"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("DLI_EMPLOYEE_PORTAL_EMPLOYEE_INFORMATION"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EID", Session["sessionEMPID"].ToString());
cmd.Connection = con;
con.Open();
SqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
string EMP_FIRST = dataReader["FIRST_NAME"].ToString();
string EMP_LAST = dataReader["LAST_NAME"].ToString();
string EMP_DEPT = dataReader["DEPT"].ToString();
string EMP_DEPT_ID = dataReader["DEPT_ID"].ToString();
body = body + "<p>SUBMITTED BY : (" + Session["sessionEMPID"].ToString() + ") " + EMP_FIRST + " " + EMP_LAST + " - DEPT : " + EMP_DEPT + "</p> " + System.Environment.NewLine;
}
con.Close();
}
}
I just need to query one row based of an employee ID.. and I would rather do it not by stored procedure but a select query.
SELECT e.FIRST_NAME, e.LAST_NAME, e.DEPT_ID, d.NAME
FROM EMPLOYEE AS e
INNER JOIN DEPARTMENT AS d ON e.DEPT_ID = d.ID
WHERE (e.ID = 'sim01')
I am building an HTML body string so that is why I need the information.
body = body + "<p>SUBMITTED BY : (" + Session["sessionEMPID"].ToString() + ") " + EMP_FIRST + " " + EMP_LAST + " - DEPT : " + EMP_DEPT + "</p> " + System.Environment.NewLine;
Any help is greatly appreciated. Thank you.
If all you want to do is use a query instead of a stored procedure, just pass your SQL statement to the Command and set your CommandType to Text. If you only ever expect one row, use if (dataReader.Read() instead of while (dataReader.Read()).
string constr = ConfigurationManager.ConnectionStrings["PAYROLL"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(
"SELECT e.FIRST_NAME, e.LAST_NAME, e.DEPT_ID, d.NAME " +
"FROM EMPLOYEE AS e " +
"INNER JOIN DEPARTMENT AS d ON e.DEPT_ID = d.ID " +
"WHERE (e.ID = #EID)"));
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#EID", Session["sessionEMPID"].ToString());
cmd.Connection = con;
con.Open();
SqlDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (dataReader.Read())
{
string EMP_FIRST = dataReader["FIRST_NAME"].ToString();
string EMP_LAST = dataReader["LAST_NAME"].ToString();
string EMP_DEPT = dataReader["DEPT"].ToString();
string EMP_DEPT_ID = dataReader["DEPT_ID"].ToString();
body = body + "<p>SUBMITTED BY : (" + Session["sessionEMPID"].ToString() + ") " + EMP_FIRST + " " + EMP_LAST + " - DEPT : " + EMP_DEPT + "</p> " + System.Environment.NewLine;
}
con.Close();
}
}
If the query can return more than one row, you can add TOP 1 to the query with an ORDER BY <some other field> to grab only the most relevant one.
It us better to use query instead of stored procedure if there is no TSQL logic
I'm having trouble with this method. It returns empty string, what is wrong with this ?
I have this method:
public static string GetData(string Table1, string Column1, string WhereColumn, string WhereValue)
{
Table1 = Methods.cleaninjection(Table1); // Some injection method that cleans the string
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["connection"].ConnectionString);
SqlCommand command = new SqlCommand("SELECT " + "#Column1" + " FROM " + Table1 + " WHERE " + "#WhereColumn" + " = " + "#WhereValue", connection);
command.Parameters.AddWithValue("Column1", Column1);
command.Parameters.AddWithValue("WhereColumn", WhereColumn);
command.Parameters.AddWithValue("WhereValue", WhereValue);
try
{
if ((connection.State == ConnectionState.Closed) || (connection.State == ConnectionState.Broken))
{
connection.Open();
}
string veri = Convert.ToString(command.ExecuteScalar());
return veri;
}
finally
{
connection.Close();
}
}
When I run this, the command string looks like this:
SELECT #Column1 FROM Table1 WHERE #WhereColumn = #WhereValue
It looks like correct but I couldn't find what is wrong.
Any ideas?
As commented, you cannot parameterize your column names and table names. Instead, do string concatenation:
"SELECT " + Column1 + " FROM " + Table1 + " WHERE " + WhereColumn + " = #WhereValue";
Here is how your code should be:
public static string GetData(string Table1, string Column1, string WhereColumn, string WhereValue)
{
Table1 = Methods.cleaninjection(Table1); // My injection method that cleans the string
string sql = "SELECT " + Column1 + " FROM " + Table1 + " WHERE " + #WhereColumn + " = #WhereValue";
using (SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["connection"].ConnectionString))
{
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#WhereValue", SqlDbType.VarChar, 50).Value = WhereValue;
connection.Open();
string veri = Convert.ToString(command.ExecuteScalar());
return veri;
}
}
}
Notes:
Please do not use AddWithValue. Use Parameters.Add() instead. According to this article:
There is a problem with the AddWithValue() function: it has to infer
the database type for your query parameter. Here’s the thing:
sometimes it gets it wrong.
Wrap your object in Using to ensure proper cleanup of resources.
For additional security purposes, you can wrap your column name and table name in square brackets [].
i was trying to update two tables at once, but i got some syntax error on update code could u give me some idea? the insert code works perfect and i tried to copy the insert code and edit on update button clicked
here is my code
private void button2_Click(object sender, EventArgs e)
{
System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection();
conn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data source= C:\Users\user\Documents\Visual Studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1\crt_db.accdb";
try
{
conn.Open();
String Name = txtName.Text.ToString();
String AR = txtAr.Text.ToString();
String Wereda = txtWereda.Text.ToString();
String Kebele = txtKebele.Text.ToString();
String House_No = txtHouse.Text.ToString();
String P_O_BOX = txtPobox.Text.ToString();
String Tel = txtTel.Text.ToString();
String Fax = txtFax.Text.ToString();
String Email = txtEmail.Text.ToString();
String Item = txtItem.Text.ToString();
String Dep = txtDep.Text.ToString();
String k = "not renwed";
String Remark = txtRemark.Text.ToString();
String Type = txtType.Text.ToString();
String Brand = txtBrand.Text.ToString();
String License_No = txtlicense.Text.ToString();
String Date_issued = txtDate.Text.ToString();
String my_querry = "update crtPro set Name='" + Name + "',AR='" + AR + "',Wereda='" + Wereda + "',Kebele='" + Kebele + "',House_No='" + House_No + "',P_O_BOX='" + P_O_BOX + "',Tel='" + Tel + "',Fax='" + Fax + "',Email='" + Email + "',Item='" + Item + "',Dep='" + Dep + "','" + k + "',Remark='" + Remark + "' where Name='" + Name + "' ";
OleDbCommand cmd = new OleDbCommand(my_querry, conn);
cmd.ExecuteNonQuery();
String my_querry1 = "SELECT max(PID) FROM crtPro";
OleDbCommand cmd1 = new OleDbCommand(my_querry1, conn);
string var = cmd1.ExecuteScalar().ToString();
String ki = txtStatus.Text.ToString();
String my_querry2 = "update crtItemLicense set PID=" + var + ",Type='" + Type + "',Brand='" + Brand + "',License_No='" + License_No + "',Date_issued='" + Date_issued + "' where PID=" + var + "";
OleDbCommand cmd2 = new OleDbCommand(my_querry2, conn);
cmd2.ExecuteNonQuery();
MessageBox.Show("Message added succesfully");
}
catch (Exception ex)
{
MessageBox.Show("Failed due to" + ex.Message);
}
finally
{
conn.Close();
}
The most likely problem based on the little information given (what database are you using for example - SQL Server 2012?), is that the datatype you are providing in the concatenated dynamic sql does not match the datatype of the column in the database. You've surrounded each value with quotes - which means it will be interpreted as a varchar. If you've got a date value in the wrong format (ie if Date_Issued is a date column) or if it is a number column, then it will error.
The solution is to replace your dynamic SQL with a parameterized query eg:
String my_querry = "update crtPro set Name=#name, AR=#ar, Wereda=#Wereda, etc ...";
OleDbCommand cmd = new OleDbCommand(my_querry, conn);
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#name", Name);
cmd.Parameters.AddWithValue("#myParam", Convert.ToDateTime(txtDate.Text.Trim()));
...
cmd.ExecuteNonQuery();
You can read about it further here
PS Make sure your parameters are in the same order as they are used in the SQL, because oledbcommand doesn't actually care what you call them. see here
I created this function that inserts new records -- I submit query directly to it.
My question- is it optimal? It is it fool proof and guaranteed to function normally? If not; please advise.
static String Server = "";
static String Username = "";
static String Name = "";
static String password = "";
static String conString = "SERVER=" + Server + ";DATABASE=" + Name + ";UID=" + Username + ";PASSWORD=" + password + ";connect timeout=500000;Compress=true;";
public bool InsertSQL(String Query)
{
int tmp = 0;
try
{
using (MySqlConnection mycon = new MySqlConnection(conString))
{
using (MySqlCommand cmd = new MySqlCommand(Query, mycon))
{
mycon.Open();
try
{
tmp = cmd.ExecuteNonQuery();
}
catch
{
if (mycon.State == ConnectionState.Open)
{
mycon.Close();
}
}
mycon.Close();
}
}
}
catch { return tmp > 0 == true ? true : false; }
return tmp > 0 == true ? true : false;
}
This is my SQL insert that I create in other function and pass as text to insert function. I am open to all suggestions!
String insertSql = #"INSERT INTO `gps_unit_location`
(`idgps_unit`,`lat`,`long`,`ip`,`unique_id`,
`loc_age`,`reason_code`,`speed_kmh`,
`VehHdg`,`Odometer`,`event_time_gmt_unix`,`switches`, `engine_on_off`, `dt`)
VALUES
(
(Select idgps_unit from gps_unit where serial=" + serial + "),'" + lat + "','" + lon + "','" + IP + "','" + unique_id + #"',
'" + LocAge_mins + "','" + ReasonCode + "','" + Speed + #"',
'" + VehHdg + "','" + Odometer + "','" + EventTime_GMTUnix + "','" + Switches + "', '" + engine_on_off + #"', DATE_ADD(NOW(), INTERVAL 1 HOUR))
";
I built this answer using your code as the example. Take note of the following line:
cmd.Parameters.AddWithValue("#queryParam", Query);
It is always a best-practice to code for potential SQL Injection attacks even if they are unlikely to happen.
static String Server = "";
static String Username = "";
static String Name = "";
static String password = "";
static String conString = "SERVER=" + Server + ";DATABASE=" + Name + ";UID=" + Username + ";PASSWORD=" + password + ";connect timeout=500000;Compress=true;";
public bool InsertSQL(String Query)
{
int tmp = 0;
try
{
using (MySqlConnection mycon = new MySqlConnection(conString))
{
using (MySqlCommand cmd = new MySqlCommand(Query, mycon))
{
mycon.Open();
try
{
cmd.Parameters.AddWithValue("#queryParam", Query);
tmp = cmd.ExecuteNonQuery();
}
catch
{
if (mycon.State == ConnectionState.Open)
{
mycon.Close();
}
}
mycon.Close();
}
}
}
catch { return tmp > 0 == true ? true : false; }
return tmp > 0 == true ? true : false;
}
By making this so generic, you are leaving yourself open to SQL injection. I am guessing you have to build the query and insert values directly. SQL parameters would be better here, you could potentially pass in a params of SqlParameters, however that would still rely on generic text being sent and still leaves you open to an injection.
Here is a SQL Parameter example
I am trying to perform dynamic sql select where I am selecting from a table using a parameter.
SELECT null FROM #TableName
However I am getting error must declare table variable #TableName. I suspect this is because I am selecting from a table using a variable. I have not needed to do this before.
List<SqlParameter> sqlParams = new List<SqlParameter>()
{
new SqlParameter("TableName", "testtable"),
new SqlParameter("FieldName", "testfield"),
new SqlParameter("Find", "testfind"),
};
string sqlSelect = "SELECT null FROM #TableName
WHERE #FieldName LIKE '%' + #Find + '%' ";
DataTable dtSelect = SqlHelper.ExecuteDataset(sqlConn, CommandType.Text,
sqlSelect, 30, sqlParams.ToArray()).Tables[0];
//30 = timeout
How can I perform the above using dynamic sql? (no stored procedures please)
You cannot use parameters for things like table and column names. For those you could have a whitelist of possible values and then use string concatenation when building the SQL query.
You can't use parameters like that, so you have to build the query as a string. You could do that in SQL, but you can also just create the string in the C# code.
Make sure that the table name and field name are safe and trusted values, and doesn't come directly from an unsafe source like a web request.
string tableName = "testtable";
string fieldName = "testfield";
List<SqlParameter> sqlParams = new List<SqlParameter>() {
new SqlParameter("Find", "testfind"),
};
string sqlSelect =
"SELECT null " +
"FROM " + tableName + " " +
"WHERE " + fieldName + " LIKE '%' + #Find + '%' ";
private DataTable ExecuteDynamic(string TableName,string FieldName, string Find)
{
string sqlSelect = "SELECT * FROM " + TableName +
" WHERE " + FieldName + " LIKE '%'" + Find + "'%' ";
using (connection = new SqlConnection(Strcon))
connection.Open();
{
using (cmd = new SqlCommand(sqlSelect, connection))
{
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 60;
adpt = new SqlDataAdapter(cmd);
dt = new DataTable();
adpt.Fill(dt);
return (dt);
}
}
}