I'm using Sqlite as my database of choice in a C# forms app, with http://sqlite.phxsoftware.com/ System.Data.SQLite provider. I'm trying to implement a search function, but it's not playing nice... or I'm missing something.
The simplified sql I'm using looks like this:
SELECT *
FROM Table
WHERE column LIKE #boundParameter ESCAPE '!'
When I run this, in any permutation with a parameter (using ? or ?001 or :boundParameter or #boundParameter), it gives me a FormatException: "Input string was not in a correct format." I haven't been able to find anything that says I can't use parameters with LIKE. Anyone know something about this? Do I need to do it some other way?
I would recommend trying something like this:
"SELECT * FROM [Table] WHERE [column] LIKE #boundParameter ESCAPE #escape";
and then:
command.Parameters.AddWithValue("#boundParameter", parameter));
command.Parameters.AddWithValue("#escape", "!");
Parameters.AddWithValue is the SQLite way of adding a bound parameter, rather than having to declare a new one each time.
#Noah (sorry, can't comment yet)
Stephen Jennings is right, you don't have to quote the value you are binding.
How do you connect and add parameters?
I haven't been using SQLite much, but the following should work;
SQLiteCommand command = _yourConnection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "SELECT * FROM Table WHERE column LIKE #boundParameter";
command.Parameters.Add(new SQLiteParameter("#boundParameter", _yourSearchCriteria));
...
"Input string was not in a correct format" is not an error message returned by any version of SQLite
It must be being returned by the wrapper. SO ... I am going to guess that you are using the ADO.NET 2.0 Provider from sqlite.phxsoftware.com
You must remember to quote the value you are binding to the parameter.
For example, if you use
command.Parameters.Add(new SQLiteParameter("#boundParameter", _pattern));
then _pattern = "'test'" and not "test"
This program-code executes a query, that includes PARAMETER SUBSTITUTION and PATTERN FITTING in one step. Here, the string variable myNamePattern is the string that we wanna find the customers for, so that all returned customers will INCLUDE THE variable myNameattern string. I had the same problem, but i solved it! This is the perfect way, to substitute a string pattern (that is also a parameter) into SQLiteCommand.CommandText:
SQLiteCommand command = conn.CreateCommand();
command.CommandText = "select * from Customer where name like #myStringParameter";
command.Parameters.Add("myStringParameter", System.Data.DbType.String).Value = "%"+ myNamePattern+ "%";
Related
I was reminding myself of the syntax for parameterized queries (C# OleDB library), and the first couple of examples I stumbled across were straight-forward, but I noticed something about the syntax:
sqlCommand.CommandText = "SELECT * FROM Customer WHERE Name LIKE #Name;";
sqlCommand.Parameters.AddWithValue("#Name", "%" + searchString + "%");
What I noticed was the SQL format for identifying what will be replaced with the parameters was different from what I have been typically using. I typically use a colon and square brackets:
sqlCommand.CommandText = "SELECT * FROM Customer WHERE [Name] LIKE :Name;";
sqlCommand.Parameters.AddWithValue(":Name", "%" + searchString + "%");
Now, the two examples I was looking at with the '#' were from sql-server examples, where I normally only work with Access and Oracle. But I saw other access examples using the '#' as well.
Does it really make any difference, or is it just a style thing? I recall that (using access at least) the engine ignores the parameter names and just inserts the parameters in the order that they are listed.
I note from the MSDN that:
The OLE DB.NET Framework Data Provider uses positional parameters that are marked with a question mark (?) instead of named parameters.
This reinforces my view that the parameter name / syntax doesn't matter and is ignored. However, even if this is correct, is there a good habit to get into that provides more robustness for other frameworks etc?
Obviously parameterizing queries is important to help prevent you from sql-injection. Different databases use different constructs to use parameters. For example SQL-Server uses the "#" as a place-holder for a parameter but DOES allow for parameters to be named... likewise, others may use ":" also as a named-place-holder. However, with OleDB, it uses a single "?" as the place-holder and is NOT named. Therefore, you must add your parameters in exact order as they represent in your query command.
Also, I have found instances when using NAMED parameters, that if you have a column and parameter by the same, it might not work as intended as the database might resolve itself by the column -- which is not the intended purpose. Rename the parameter with some prefix (or suffix) to help clarify. Such example might be..
sqlCommand.CommandText = "update MyCustomerTable set email = #email where customerID = #customerID";
sqlCommand.Parameters.AddWithValue("email", "someValue#anywhere.com");
sqlCommand.Parameters.AddWithValue("customerID", someIDValue );
Also note.. you don't actually include the "#" or ":" for named parameters. The engines will know how to handle them.
all looks good, but to prevent ambiguity if the "parameter" is not found and it falls back on the column name, try..
sqlCommand.CommandText = "update MyCustomerTable set email = #parmEmail where customerID = #parmCustomerID";
sqlCommand.Parameters.AddWithValue("parmEmail", "someValue#anywhere.com");
sqlCommand.Parameters.AddWithValue("parmCustomerID", someIDValue );
This way there is no confusion.
Now, back to the "?" place-holder. If you have a single parameter value that is applied multiple times, you need to add the parameter for each instance. If named parameters are allowed, you might get away with..
sqlCommand.CommandText =
#"update SomeTable
set Rate1 = Rate1 * #newRateFactor,
Rate2 = Rate2 * #newRateFactor";
sqlCommand.Parameters.AddWithValue("newRateFactor", 1.15);
Notice only a single named-parameter is required... but with the "?", you have to add it EACH TIME
sqlCommand.CommandText =
#"update SomeTable
set Rate1 = Rate1 * ?,
Rate2 = Rate2 * ?";
sqlCommand.Parameters.AddWithValue("ratePlaceHolder1", 1.15);
sqlCommand.Parameters.AddWithValue("ratePlaceHolder2", 1.15);
Doing things like sql inserts and updates can also get tricky when you have a bunch of parameters for all column names. You can still give a parameter NAME value, but it must be in the same ordinal position within the query for execution.
This reinforces my view that the parameter name / syntax doesn't matter and is ignored.
That is certainly not true. The parameter prefix you are using does matter, but ODBC is a little more relax on that since it has to support a lot of platforms. Never ever assume though you can just throw in any garbage, because it will bite you.
You indeed have to use the ? for parameters in OLE DB. The names you give when supplying the parameters are ignored, the order is all that matters there.
i am doing a program in C# and i´m trying to execute a query in a DBF files that i think is ok but the value of the HasRows property of the DataReader is false. I think the problem is with the dates. This is my code:
string Con = #"Provider=VFPOLEDB.1;Data Source=\\Server\ges_01";
OleDbConnection ConnectionHandler = new OleDbConnection(Con);
ConnectionHandler.Open();
string SQL = "SELECT codalb FROM BALBARA WHERE FECALB BETWEEN CTOD('2015/12/07') AND CTOD('2015/12/13') AND CODCLI LIKE '%9' ORDER BY CODALB"
OleDbCommand Query = new OleDbCommand(SQL, ConnectionHandler);
OleDbDataReader datareader = Query.ExecuteReader();
while(datareader.Read())
{}
I know the rest is ok because if put string SQL="select codalb from balbara"; Works fine.
Any one can say me what i´m doing wrong
The problem here is that the CTOD() function isn't supported by the OLE DB Provider.
Change your query to use DTOS() which:
Returns a character-string date in a yyyymmdd format from a specified
Date or DateTime expression.
So concluding your query might become to:
string SQL = String.Format(
#"SELECT
codalb
FROM
balbara
WHERE
DTOS(fecalb) BETWEEN '{0}' AND '{1}'
AND codcli LIKE '%9'
ORDER BY
codalb",
dateTimeVariable1.ToString("yyyyMMdd"),
dateTimeVariable2.ToString("yyyyMMdd"));
Note 1: check out the indenting to help you write readable code, also I suggest to write all the column/table names lowercase so you can make an easy difference what is your "data" and what is SQL.
Note 2: you can find offical format string examples about the DateTime type here.
EDIT: As a good advice in comments from #AlanB, you should always strive to use parametrized queries instead of a string to prevent SQL Injection attacks.
A remark about the OLEDB parameters:
The OLE DB .NET Provider does not support named parameters for passing
parameters to an SQL statement or a stored procedure called by an
OleDbCommand when CommandType is set to Text. In this case, the
question mark (?) placeholder must be used.
And about the order of parameters:
Therefore, the order in which OleDbParameter objects are added to the
OleDbParameterCollection must directly correspond to the position of
the question mark placeholder for the parameter in the command text.
So all these informations given your query could look this example:
OleDbCommand Query = new OleDbCommand();
Query.Connection = ConnectionHandler;
Query.CommandText =
#"SELECT
codalb
FROM
balbara
WHERE
DTOS(fecalb) BETWEEN ? AND ?
AND codcli LIKE '%9'
ORDER BY
codalb";
Query.Parameters.Add(dateTimeVariable1.ToString("yyyyMMdd"));
Query.Parameters.Add(dateTimeVariable2.ToString("yyyyMMdd"));
OleDbDataReader datareader = Query.ExecuteReader();
I am struggling with proper parameter passing to a MySQL query. In MySQL workbench, my query works fine, but not in the C# code. I assume it is due to wrong parameter passing.
That's why I'd like to see what precisely do I pass to the cmd.ExecuteScalar() method. But I can't figure out how to determine the cmd string.
In debugger I only get query with formal parameters, not passed ones. And even by using cmd.ToString() I get this nonsense:
MySql.Data.MySqlClient.MySqlCommand.
Here is my code:
string timeStampStr = timeStamp.ToString("yyyy-MM-dd hh:mm:ss");
...
MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) FROM plc WHERE plc.last_communication < #timeThreshold AND plc.id = #plcId", _conn);
cmd.Parameters.AddWithValue("#timeThreshold", timeStampStr); // Is this correct ? timeStampStr is a string
cmd.Parameters.AddWithValue("#plcId", plcId);
object result = cmd.ExecuteScalar();
Thank you !
Your best bet is probably to enable the query log on MySQL and use that to profile what was sent to the database engine.
This is because the application code doesn't actually replace the placeholders with the parameter values, the database engine does. The application code invokes the parameterized query and supplies the parameters simultaneously. (As a bit of a side-effect, this allows database engines to cache execution plans for parameterized queries much more effectively, since the query itself doesn't change. This provides a slight performance improvement when using parameterized queries over concatenated values.)
And even by using cmd.ToString() I get this nonsence: MySql.Data.MySqlClient.MySqlCommand.
That's not nonsense, that's the name of the class on which you're calling .ToString(). The default behavior of .ToString() for reference types is to return the name of the type, unless you override it.
I am trying to use ALTER USER query for Oracle database using OracleCommand in C# in the following code. It creates the query if the values for Username and password are not empty strings. But I get an error "ORA-01036: illegal variable name/number" when ExecuteNonQuery() is executed.
string updateQuery = "ALTER USER :user IDENTIFIED BY :password";
connection = new OracleConnection(LoginPage.connectionString);
connection.Open();
OracleCommand cmd = new OracleCommand(updateQuery, connection);
cmd.Connection = connection;
for(int i=0;i<usersList.Count;i++)
{
if (!(selectedUsersArray[i].Equals("")) && !passwordArray[i].Equals(""))
{
OracleParameter userName = new OracleParameter();
userName.ParameterName = "user";
userName.Value = selectedUsersArray[i];
OracleParameter passwd = new OracleParameter();
passwd.ParameterName = "password";
passwd.Value = passwordArray[i];
cmd.Parameters.Add(userName);
cmd.Parameters.Add(passwd);
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
Could you please suggest what is wrong with my implementation?.
The root cause
In Oracle you have three kinds of SQL statements (and additionally there are PL/SQL blocks):
Statements in the Data Definiton Language (DDL). These statements modify the structure of the database. They begin usually with the verbs "ALTER" or "CREATE"
Statements in the Data Modification Langugage (DML). There statements modify the content inside of tables, leaving the structure of each table unmodified. These statements usually begin with "INSERT", "MERGE" or "DELETE".
Statements in what I call "query language" (there seems to be no canonical name for these). This statements start with the verb "SELECT".
Bind variables in Oracle are only allowed in some special places in DML and query statements. You are trying to use bind variables in a places where they are not allowed. Hence the error.
Solution
Build your statement without bind variables. Build the complete query string instead using string concatenation.
If you want to sanitize the input before concatenating the string, use the DBMS_ASSERT package.
Background
Bind variables can only be used when Oracle can build a query plan without knowing the value of the variable. For DDL statements, there is no query plan. Hence bind variables are not allowed.
In DML and query statements, bind variables are only allowed, when they are used inside a tuple (regarding the underlying set theory), i.e. when the value will be compared with the value in a table or when the value will be inserted in a table. They are not allowed to change the structure of the execution plan (e.g. to change the target table or to change the number of comparisons).
Just for others getting this error and looking for info on it, it is also thrown if you happen to pass a binding parameter and then never use it. I couldn't really find that stated clearly anywhere but had to prove it through trial and error.
I just spent several days checking parameters because I have to pass 60 to a stored procedure. It turns out that the one of the variable names (which I load into a list and pass to the Oracle Write method I created) had a space in the name at the end. When comparing to the variables in the stored procedure they were the same, but in the editor I used to compare them, I didnt notice the extra space. Drove me crazy for the last 4 days trying everything I could find, and changing even the .net Oracle driver. Just wanted to throw that out here so it can help someone else. We tend to concentrate on the characters and ignore the spaces. . .
You defined one oracleCommand but used it in 'for'.
it means you are adding parameter with the same name to one OracleCommand.
you should use cmd.Parameters.clear() to refresh your parameters.
for(int i=0;i<usersList.Count;i++)
{
if (!(selectedUsersArray[i].Equals("")) && !passwordArray[i].Equals(""))
{
cmd.Parameters.clear();//Add this line
OracleParameter userName = new OracleParameter();
userName.ParameterName = "user";
userName.Value = selectedUsersArray[i];
OracleParameter passwd = new OracleParameter();
passwd.ParameterName = "password";
passwd.Value = passwordArray[i];
cmd.Parameters.Add(userName);
cmd.Parameters.Add(passwd);
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
The Oracle error ORA-01036 means that the query uses an undefined variable somewhere. From the query we can determine which variables are in use, namely all that start with #. However, if you're inputting this into an advanced query, it's important to confirm that all variables have a matching input parameter, including the same case as in the variable name, if your Oracle database is Case Sensitive.
This error happens when you are also missing cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("GUSERID ", OracleType.VarChar)).Value = userId;
I was having eight parameters and one was with space at the end as shown in the above code for "GUSERID ".Removed the space and everything started working .
I was having the same problem in an application that I was maintaining, among all the adjustments to prepare the environment, I also spent almost an hour banging my head with this error "ORA-01036: illegal variable name / number" until I found out that the application connection was pointed to an outdated database, so the application passed two more parameters to the outdated database procedure causing the error.
You cannot pass user/table name to pl/sql with a parameter. You can create a procedure and build sql and then execute immediately to achieve that.
I have faced same problem ... For the problem is like this, I am calling the PRC inside cpp program and my PRC taking 4 arguments but while calling I used only 1 arguments so this error came for me.
Begin Example_PRC(:1); End; // this cause the problem
Begin Example_PRC(:1,:2,:3,:4); End; // this is the solution
I had the same issue today when using Python module cx_Oracle. In my case, the root cause was an invalid variable name.
Example: SELECT * FROM DATA WHERE KEY IN (:_0, :_1, ...)
When I changed _0 to var0, it worked fine.
From this blog post, I found these rules for variable names:
Must start with a letter
Maximum size is limited to 30 letters
Cannot contain whitespace characters
Can contain dollar sign ('$'), underscore ('_') and hash sign ('#')
Is case-insensitive
I had the same problem, was learning connection to oracledb.
previous code-
SELECTALLCANDIDATES = "Select * from candidate_master";
data= await connection.execute(SELECTALLCANDIDATES, {autoCommit:true})
Removed the {autoCommit:true} and it started working fine.Correct code-
SELECTALLCANDIDATES = "Select * from candidate_master";
data= await connection.execute(SELECTALLCANDIDATES)
Still don't know why but it works.
Check your named variables match, I had the same problem, I had a spelling mistake/typo in one of my parameters
Below is an insert statement that is inputting the first value (acctNum) into the second column (itemCode) and vice versa:
string addUpcCode = "INSERT INTO compare1 (acct, itemcode)"
+ "VALUES ('"+acctNum+"', '"+itemCode+"')";
This is not how I want it to work, as I want the first value to go in the first column and the second in the second column. How can I go about this?
Side note: This is a rough draft until I learn more about parameterization. I won't be releasing this code until I learn and implement it.
The given SQL snipplet will do what you want - especially the sequence of columns will be preserved.
I suspect you might have switched your variables, leading to the same phenomen but out of an other reason.
You should use SQL Parameters which also avoids creating a SQL injection problem:
using (SqlCommand command = new SqlCommand("INSERT INTO compare1 (acct, itemcode) VALUES (#AcctNum, #ItemCode)", connection))
{
// Add new SqlParameter to the command.
command.Parameters.Add(new SqlParameter("AcctNum", acctNum));
command.Parameters.Add(new SqlParameter("ItemCode", itemCode));
As you're using C# the string.format function is perfect for this kind of thing
string.format("INSERT INTO compare1(acct, itemCode) Values('{0}','{1}'", acctNum, itemCode);
or
string.format("INSERT INTO compare1 SELECT '{0}','{1}' ", acctNum, itemCode);
But yeah, you probably have them mixed up somewhere else, the order will be kept. Oh and if acctNum is an integer, you won't need the quotation marks around {0}
Edit:
Oh and yeah, definitely look into parameters next
Use parametrized queries to prevent SQL injection and you can solve this matter
command.Parameters.Add("AcctNum", acctNum);