SQLParameter incorrect syntax - c#

I have 2 spots where I need to use SQLParameter to parse SQL. One works and one does not and I cannot figure out why the second one doesn't work.
The first one that works is the following:
SqlCommand getShopDbNameCommand = new SqlCommand("SELECT TOP 1 [mappeddbName] FROM [ECM].[dbo].[EcmShop]" +
"WHERE [LicencePassCode] = #licCode AND [iPadLocation] = #shopId", this.mainConnection);
getShopDbNameCommand.Parameters.Add(new SqlParameter("licCode", currUser.LicCode));
getShopDbNameCommand.Parameters.Add(new SqlParameter("shopId", currUser.ShopID));
That works. On top of that, the majority of the tutorials I've read all say that I do not have to have a # in front of the parameter name inside of the new SqlParameter, only inside of the command text itself do I need a # in front of the parameter name.
The second command I am trying to run is the following:
string getAuthCommandText = "SELECT * FROM [" + shopDbName + "].[dbo].[MessageLink]" +
"WHERE [objectname] LIKE %" + "#compareStringA"+ "% OR [objectname] LIKE %" + "#compareStringB" +"%";
SqlCommand getAuthCommand = new SqlCommand(getAuthCommandText, this.mainConnection);
getAuthCommand.Parameters.Add(new SqlParameter("compareStringA", "ABRAUTH"));
getAuthCommand.Parameters.Add(new SqlParameter("compareStringB", "ABRSAUTH"));
This does not work and throws an invalid syntax error. Using breakpoints it still looks like the command is trying to pass the literal #compareString string to SQL and thats whats causing the issue. Ive seen other posts on SOF that say to use the literal parameter name when defining new SqlParameter objects (meaning include the #) but everywhere outside of SoF say otherwise.
Any reason why the second command would throw invalid syntax errors?

your LIKE statements must be inside single quotes
SELECT * FROM Customers WHERE City LIKE '%s%';

the majority of the tutorials I've read all say that I do not have to have a # in front of the parameter name inside of the new SqlParameter,
The C# code for SqlParameter does not care if you put a # in the front or not when adding it to the Parameters collection, it will put a # behind the scenes for you.
For your query that is not working the correct way to do it is you will actually have 3 strings you add together in sql, the two '%' and your parameter. I am also changing the way you add parameters to explicitly set the data type, it is better to do that with strings.
string getAuthCommandText = "SELECT * FROM [" + shopDbName + "].[dbo].[MessageLink]" +
"WHERE [objectname] LIKE ('%' + #compareStringA + '%') OR [objectname] LIKE ('%' + #compareStringB +'%')";
SqlCommand getAuthCommand = new SqlCommand(getAuthCommandText, this.mainConnection);
getAuthCommand.Parameters.Add("#compareStringA", SqlDbType.VarChar, 20).Value = "ABRAUTH"; //I had to guess on your datatype, I just did varchar(20), change as appropriate.
getAuthCommand.Parameters.Add("#compareStringB", SqlDbType.VarChar, 20).Value = "ABRSAUTH";

Try this:
string getAuthCommandText = "SELECT * FROM [" + shopDbName + "].[dbo].[MessageLink] " +
"WHERE [objectname] LIKE " + "#compareStringA"+ " OR [objectname] LIKE " + "#compareStringB" +"";
SqlCommand getAuthCommand = new SqlCommand(getAuthCommandText, this.mainConnection);
getAuthCommand.Parameters.Add(new SqlParameter("compareStringA", "%ABRAUTH%"));
getAuthCommand.Parameters.Add(new SqlParameter("compareStringB", "%ABRSAUTH%"));

Related

Can you tell whats wrong with the SqlDataReader i returns "System.Data.SqlClient.SqlException: 'Must declare the scalar variable "#idorder"

Hi since I am using the using-statement, my disposable connections should be handled once it leaves the statement but my code is hard coupled in other methods in the program where I poll the db or get information. Therefore I have decided to add conn.Open() and conn.Close() to avoid timeout errors or to leave many Database connections open at the same time. I keep getting an error I am not familiar with and that is:
System.Data.SqlClient.SqlException: 'Must declare the scalar variable "#idorder"
Is it relevant to my paramenter?
What am I doing wrong?
Hope this helps other devs out there starting out with ADO.NET
public List<LogModel> GetLatestLogsOnEachSystemId(
{
List<string> _systemIds = new List<string>();
_systemIds.Add("MA");
_systemIds.Add("MB");
_systemIds.Add("DY");
_systemIds.Add("FA");
using (SqlConnection conn = new SqlConnection(connString))
{
for (int i = 0; i < _systemIds.Count; i++)
{
string systemId = _systemIds[i];
var querystring = "select top 1 * " +
"from dbo.RadarMF30_log " +
"where SYSTEM_ID = #id" +
"order by Log_writing_time desc";
SqlCommand cmd = new SqlCommand(querystring, conn);
conn.Open();
cmd.Parameters.AddWithValue("#id", systemId);
SqlDataReader reader = cmd.ExecuteReader();
conn.Close();
var model = new LogModel
{
errorCode = reader.GetString(0),
errorMsg = reader.GetString(1),
"select top 1 * " +
"from dbo.RadarMF30_log " +
"where SYSTEM_ID = #id" +
"order by Log_writing_time desc";
There is no space between #id and order.
That's why it thinks there is a variable called #idorder
JamesS and Yaman have already covered the fundamental problem, but: as a general tip, if you're going to have SQL in C#, verbatim string literals (#"...") avoid almost all white-space problems:
const string query = #"
select top 1 *
from dbo.RadarMF30_log
where SYSTEM_ID = #id
order by Log_writing_time desc";
(note: it doesn't have to be a const - just... there's also no need for it to be a variable here)
As a side note: this is the kind of scenario that also works very well with tools like "Dapper" to avoid messing with ADO.NET at all:
var model = conn.QuerySingle<LogModel>(#"
select top 1 *
from dbo.RadarMF30_log
where SYSTEM_ID = #id
order by Log_writing_time desc", new { id = systemId });
No more messing with the command and parameter nuances, or worrying about whether you've closed the connection too early (look closely: you've closed the connection too early).
As a side note: you might also want to avoid select * - it can cause two different kinds of problems:
bringing back lots of large columns (CLOB/BLOB etc) that you don't need, impacting performance
sometimes, just sometimes, the columns aren't in the order you expect; if you bind by ordinal (GetString(0) etc in your code), this can have huge impact; note that "Dapper" binds by name, so this isn't as much of a problem here (assuming the names match well enough for the library to figure out what you meant)
because there is no space between #id and order, it thinks the parameter name is #idorder, which is not provided
var querystring = "select top 1 * " +
"from dbo.RadarMF30_log " +
"where SYSTEM_ID = #id " +
"order by Log_writing_time desc";
or
var querystring = "select top 1 * " +
"from dbo.RadarMF30_log " +
"where SYSTEM_ID = #id" +
" order by Log_writing_time desc";

C# SQL SELECT WHERE <variable> LIKE %Column% - format?

Currently I am using this statement:
"SELECT categoryDB, number FROM " + dbName+ " WHERE titleDBColumn ='" + titleInput+ "'";
Which helps me find strings that are similar to titleInput (which is a variable coming from the outside).
However, the values in titleDBColumn are almost always shorter strings than those coming in through titleInput.
Example:
titleDBColumn: Streetcar
titleInput: TheStreetCarIOwn
Now it's obvious that I need to use the LIKE operator in the other direction to get the results I want but I cant get the format right. Any ideas?
Sorry if I'm unclear.
This worked for me:
"SELECT categoryDB, number FROM " + dbName + " WHERE '" +
titleInput + "' like '%' + titleDBColumn + '%'";
The resulting SQL must be
SELECT categoryDB, number
FROM tableName
WHERE 'input' LIKE '%' + titleDBColumn + '%'
The % wildcard means "any number of any characters". I.e, 'input' LIKE '%' + titleDBColumn + '%' means that the input text may contain characters before and after the column text.
Also, you should use command parameters, whenever possible. This is not possible for the table name you called dbName. If this name is defined in the code and is not a user input, then it is safe to concatenate it as you did. But otherwise take measures to prevent SQL-Injection.
string sql = "SELECT categoryDB, number FROM `" + dbName +
"` WHERE #input LIKE '%' + titleDBColumn + '%'";
using (var conn = new MySqlConnection(connStr)) {
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#input", titleInput);
conn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
}
}

Creating reusable SQL commands in c# programing

I have following query that works.
string sqlCommandText = "SELECT * FROM Admin_T where AdminID =
'" + textBox.Text + "'";
It is a fix command and I cannot use it with user given Table names and Column names at run time.
What I am actually trying to make is command like
string sqlCommandText = "SELECT * FROM Admin_T where
'" + UserGivenColumnName + "' = '" + conditionTB.Text + "'";
"UserGivenColumnName" can be any column that is part of that specific table.
Trying to create flexibility so that same command can be used under different circumstances.
SqlCommand and none of related classes used by ADO.NET does not support such a functionality as far as I know.
Of course your should never build your sql queries with string concatenation. You should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
But prepared statements only for values, not column names or table names. If you really wanna put your input string to your column name, create a whitelist and use it as a validation before you put it in your query.
http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables-culture/
I think an Object-Relational Mapper (ORM) is perhaps the droid you are looking for. Entity Framework might be a good place to start.
Please also do take the time to understand what SQL injection is, as the other users have also prompted you to.
It is not returning anything as it is just comparing two strings
With the 'UserGivenColumnName' it is a string comparison
And those two strings are not equal
You can do it (column) by just not including the '
But it is still a bad idea
SQLinjection is a very real and very bad thing
string sqlCommandText =
"SELECT * FROM Admin_T where " + UserGivenColumnName + " = '" + conditionTB.Text + "'";
or
string sqlCommandText =
"SELECT * FROM Admin_T where [" + UserGivenColumnName + "] = '" + conditionTB.Text + "'";

Parametrized query from .net to Oracle

this is my table in oracle:
I'm trying to do this:
selectCmd = "select * from scott.BONUS where ename like '% :f4 %'";
var par = cmd.CreateParameter();
par.DbType = DbType.String;
par.ParameterName = "f4";
par.Value = "fsd";
cmd.Parameters.Add(par);
cmd.CommandText = selectCmd;
con.Open();
my problem is the part after the 'like' .. I've tried many things w/o success.
In some of the tries the reader came back empty while in others an exception has been thrown.
That is looking for something containing the literal sequence of characters space, colon, f, 4. You mean:
like '%' || :f4 || '%'
(edited to reflect correction by Stephen ODonnell, comments)
Or easier; just use
like :f4
And put the % in the value:
par.Value = "%" + "fsd" + "%";
(expanded for convenience, under the assumption that "fsd" needs to be a variable or similar in the real code)

Getting SQLException when debugging

I've got a error which I can't understand. When I'm debugging and trying to run a insert statement, its throwing the following exception:
"There are fewer columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement."
I have looked all over my code, and I can't find the mistake I've made.
This is the query and the surrounding code:
SqlConnection myCon = DBcon.getInstance().conn();
int id = gm.GetID("SELECT ListID from Indkøbsliste");
id++;
Console.WriteLine("LNr: " + listnr);
string streg = GetStregkode(navne);
Console.WriteLine("stregk :" + strege);
string navn = GetVareNavn(strege);
Console.WriteLine("navn :" + navne);
myCon.Open();
string query = "INSERT INTO Indkøbsliste (ListID, ListeNr, Stregkode, Navn, Antal, Pris) Values(" + id + "," + listnr + ", '" + strege + "','" + navn + "'," + il.Antal + ", "+il.Pris+")";
Console.WriteLine(il.Antal+" Antal");
Console.WriteLine(il.Pris+" Pris");
Console.WriteLine(id + " ID");
SqlCommand com = new SqlCommand(query, myCon);
com.ExecuteNonQuery();
com.Dispose();
myCon.Close();
First of all check the connection string and confirm the database location and number of columns a table has.
Suggestion : Do not use hardcoded SQL string. Use parameterized sql statements or stored-proc.
Try parameterized way,
string query = "INSERT INTO Indkøbsliste (ListID, ListeNr, Stregkode, Navn, Antal, Pris)
Values (#ListID, #ListeNr, #Stregkode, #Navn, #Antal, #Pris)"
SqlCommand com = new SqlCommand(query, myCon);
com.Parameters.Add("#ListID",System.Data.SqlDbType.Int).Value=id;
com.Parameters.Add("#ListeNr",System.Data.SqlDbType.Int).Value=listnr;
com.Parameters.Add("#Stregkode",System.Data.SqlDbType.VarChar).Value=strege ;
com.Parameters.Add("#Navn",System.Data.SqlDbType.VarChar).Value=navn ;
com.Parameters.Add("#Antal",System.Data.SqlDbType.Int).Value=il.Antal;
com.Parameters.Add("#Pris",System.Data.SqlDbType.Int).Value=il.Pris;
com.ExecuteNonQuery();
Please always use parametrized queries. This helps with errors like the one you have, and far more important protects against SQL injection (google the term, or check this blog entry - as an example).
For example, what are the actual values of strege and/or navn. Depending on that it may render your SQL statement syntactically invalid or do something worse.
It (looks like) a little more work in the beginning, but will pay off big time in the end.
Are you using danish culture settings?
In that case if il.Pris is a double or decimal it will be printed using comma, which means that your sql will have an extra comma.
Ie:
INSERT INTO Indkøbsliste (ListID, ListeNr, Stregkode, Navn, Antal, Pris) Values(33,5566, 'stegkode','somename',4, 99,44)
where 99,44 is the price.
The solution is to use parameters instead of using the values directly in you sql. See some of the other answers already explaining this.

Categories