C# SQL statement - Syntax error in query. Incomplete query clause - c#

Below is the code I have, I can't for the life of me work out what is wrong with the query.
I originally had the error "no value given for 1 or more parameters", which seems to have gone away (although again I don't even know why I was getting it).
The connection is opened prior to this code.
The parameter GVars.thisFY is a string = "FY13" - this table definitely exists.
The parameter GVars.currentDate is a DateTime = today.
Records definitely exist for this [Destination] and [Next Collection] range:
string sql;
OleDbDataAdapter adapter;
sql = "SELECT * FROM #CurFY WHERE [Destination] = #Destination AND [Next Collection] BETWEEN #NextCollectionA AND #NextCollectionB;";
// Create the command object
OleDbCommand cmd = new OleDbCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
// Add values to the fields
cmd.Parameters.AddWithValue("#CurFY", GVars.thisFY);
cmd.Parameters.AddWithValue("#Destination", "Henwood");
cmd.Parameters.AddWithValue("#NextCollectionA", GVars.currentDate);
cmd.Parameters.AddWithValue("#NextCollectionB", GVars.currentDate.AddDays(1));
adapter = new OleDbDataAdapter(cmd.CommandText, conn);
try
{
adapter.Fill(ds);
GVars.bLblLastUpdate = DateTime.Now.ToString("HH:mm:ss");
}
catch (Exception ex)
{
}
EDIT:
I have changed the code to remove the table parameter as below, still getting the "no value given for 1 or more parameters" though which I can't pin down..
EDIT2: I removed the extra stuff so the post relates only to the original question, which has been answered. I will make a new question for my strange "no value given" error

You cannot parameterize queries with names of tables, views, or columns. Only data members can be parameterized.
You need to make your SQL dynamically, e.g. like this:
sql = string.Format(
"SELECT * FROM {0} WHERE [Destination] = #Destination AND [Next Collection] BETWEEN #NextCollectionA AND #NextCollectionB;"
, GVars.thisFY
);
This should be done only if GVars.thisFY is controlled by your code, e.g. comes from a pre-defined list or checked for absence of non-alphanumeric characters to avoid SQL injection attacks.

Try this one -
sql = Sring.Format(
"SELECT * FROM {0} WHERE [Destination] = #Destination AND [Next Collection] BETWEEN #NextCollectionA AND #NextCollectionB;",
GVars.thisFY
)
cmd.Parameters.AddWithValue("#Destination", "Henwood");
cmd.Parameters.AddWithValue("#NextCollectionA", GVars.currentDate);
cmd.Parameters.AddWithValue("#NextCollectionB", GVars.currentDate.AddDays(1));

Related

Parameterized SQL queries don't work

I have posted this question already because I had problems with the "LIKE" statement but now I realized there are problems with parameterized statements at all. Here is my code:
for example when I write:
sqlCmd = new SqlCommand(#"SELECT #cusId,#cusName FROM " + form1.getTable() + " WHERE #cusId LIKE #filter", connection);
sqlCmd.Parameters.AddWithValue("cusId", form1.cusId.Text);
sqlCmd.Parameters.AddWithValue("cusName", form1.cusName.Text);
sqlCmd.Parameters.AddWithValue("filter", form1.filterType().Trim() + "%");
sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText, connection);
sqlDatAdapter.Fill(datTable);
form1.setDataGrid = datTable;
Somehow I always get
"Must declare the scalar variable #..."
for each variable when I fill the data table. I tried that already with
sqlCmd.ExecuteNonQuery();
and it seems to work in this case (when I update a database it works fine) but I need to bind the values to my DataGridView.
EDIT: Even when I just try to write something like:
... WHERE cusId.Text = #cusId
I get the same error
As noted, you aren't working with parameters quite right. Your SqlCommand should be something more like this:
SqlCommand sqlcmd = new SqlCommand(#"SELECT cusId,cusName FROM " + form1.getTable() + " WHERE cusId LIKE #filter", connection);
Note how the columns you are trying to select aren't parameters (so don't include '#' symbol).
When you add parameters you DO need to add the '#' symbol. Something like this:
sqlCmd.Parameters.AddWithValue("#cusId", form1.cusId.Text);
You can't parameterize your table and column names . You can only parameterize your values.
If you really wanna get your table and column names dynamically, you can use dynamic SQL but which is a bad idea.
Best way to get your column names dynamically is creating a strong validation for your column names or creating a black list for them.
Using ExecuteNonQuery doesn't effect anything since it's because just execute your query, does not return any data. Also use using statement to dispose your connections, commands and adapter.
Here an example;
string str = string.Format("SELECT {0}, {1} FROM {2} WHERE {0} LIKE #filter",
form1.cusId.Text,
form1.cusName.Text,
form1.getTable());
sqlCmd = new SqlCommand(str, connection);
sqlCmd.Parameters.AddWithValue("#filter", form1.filterType().Trim() + "%");
sqlDatAdapter = new SqlDataAdapter(sqlCmd);
sqlDatAdapter.Fill(datTable);
But I have to say again, you really need strong validation or black list for your column and table name when you try get them outside of your program.
I used AddWithValue in this example but this method might be dangerous in some cases. Using .Add() overloads to specify it's db type and parameter size implicitly would be better.
Finally solved it! I tried:
using (sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText, connection))
{
sqlDatAdapter.SelectCommand.Parameters.Add("#filter", SqlDbType.Int, 25).Value = CusIdEnter;
sqlDatAdapter.Fill(datTable);
form1.setDataGrid = datTable;
}
and now it works! One had to bind the parameters to the Adapter

MySQL truncate command with parameter not working

Why do I get an exception when trying to truncate a MySQL table (using MySQL Connector/Net)? I am trying to give the table name with a parameter.
This is the code I'm executing:
var connectionString = "Server="+_server+";Uid="+_user+";Pwd="+_password+";Database="+_database+";";
try
{
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
const string sql = "TRUNCATE TABLE #tablename"; // also tried with TRUNCATE #tablename
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#tablename", "test");
cmd.ExecuteNonQuery();
conn.Close();
}
}
catch (MySqlException ex)
{
Console.WriteLine(ex.ToString());
}
And this is the execption:
MySql.Data.MySqlClient.MySqlException (0x80004005): You have an error
in your SQ L syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near ''test'' at line 1
When I try a select query, for example, then I don't have any problems. This runs fine and returns correct data:
conn.Open();
const string sql = "SELECT body FROM test WHERE id=#pid";
var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#pid", 1);
cmd.ExecuteScalar();
conn.Close();
Parameters are used for query values, not object names like tables.
So this will not work for sure.
You need to set the table name in the command string by using string concatenation. You can avoid sql injection attacks by manually checking for weird characters in the table name (spaces, dashes, semicolons, etc..)
I've been playing around with this for a while now, and i can't seem to get it to work either. I can't find any documentation online, so i'm starting to think you may not be able to truncate with a parameter like you've tried.
However, is there really a need to prevent SQL injection on this command? Does the user enter the name of the table they want to truncate, and if so, they're just going to truncate a table which...is essentially what the command does anyway?

Getting "Invalid Column Name " Sql Exception in the following code

I am trying to pass both Column name and the Value to be checked in the code at runtime. However I am getting an "Invalid Column Name " exception.
The code is as follows :
string temp = TextBox1.Text.ToString();
SqlConnection con = new SqlConnection("data source=.\\SQLEXPRESS;AttachDbFilename=C:\\Users\\Sagar\\Documents\\Test.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
SqlCommand com = new SqlCommand("Select * from Employee Where #field = Sagar", con);
com.Parameters.AddWithValue("#field", DropDownList1.SelectedValue.ToString());
//com.Parameters.AddWithValue("#value", temp);
SqlDataAdapter da = new SqlDataAdapter(com);
con.Open();
SqlDataReader reader = com.ExecuteReader();
GridView1.DataSource = reader;
GridView1.DataBind();
The message says that there is no column named 'Sagar' in the table. Is there such a column? Things would be easier if you showed us the table schema instead of having us guess from the error message.
It is not possible to parameterize column names using SqlParameter in C#. This has been discussed here multiple times.
What's happening with the query the way Vidhya Sagar Reddy is doing it, is the following. He assumes that the following query
Select * from Employee Where #field = 'Sagar'
is replaced by this query when setting "Name" as the value for the #field parameter:
Select * from Employee Where Name = 'Sagar'
This, however, is wrong! What's happening is that the #field parameter is replaced as follows:
Select * from Employee Where 'Name' = 'Sagar'
This returns no results, as the WHERE clause is always false. Of course, if you use the field name Sagar, this akways returns true, as the statement then reads:
Select * from Employee Where 'Sagar' = 'Sagar'
Here's an easy test to prove what I've said above. Use the following statement to set the #field parameter (supposed, there's no column named eirghoerihgoh in the table):
com.Parameters.AddWithValue("#field", "eirghoerihgoh");
If the query executes correctly (maybe not returning any results), the above is correct. If it was not correct, an exception should be thrown about the eirghoerihgoh column not being present.
Thank you Vidhya Sagar Reddy for proving my point. By using this line
com.Parameters.AddWithValue("#field", "eirghoerihgoh");
you say you didn't get any results, but you also didn't get an exception. However, if the statement really had been changed to
Select * from Employee Where eirghoerihgoh = 'Sagar'
there had to be an exception saying that there was no column named eirghoerihgoh. As you didn't get that exception, there's only one possible explanation: The statement was changed to
Select * from Employee Where 'eirghoerihgoh' = 'Sagar'
and this executes, but doesn't return results, as the condition is always false.
Instead you can make your code this way, which works perfectly:
"Select * from Employee Where "+DropDownList1.SelectedValue.ToString()+" =
'Sagar'" – Vidhya Sagar Reddy
The reason for that is quite simple, the value that are to be specified in SQL should be in single quotes and this is a simple mistake by the way..!!!!
SqlCommand com = new SqlCommand("Select * from Employee Where #field = 'Sagar'", con);
And even change the parameter to "field" in the following line and not "#field"..!!
com.Parameters.AddWithValue("field", DropDownList1.SelectedValue.ToString());
This is working..>!!!!

why we use "#" while inserting or updating or deleting data in sql table

I just want to know why we use "#" while inserting or updating or deleting data in sql table, as I used #name like below.
cmd.Parameters.Add(new SqlParameter("#fname", txtfname.Text));
See: SqlParameter.ParameterName Property - MSDN
The ParameterName is specified in the form #paramname. You must
set ParameterName before executing a SqlCommand that relies on
parameters.
# is used by the SqlCommand so that the value of the parameter can be differentiatd in the Command Text
SqlCommand cmd = new SqlCommand("Select * from yourTable where ID = #ID", conn);
^^^^^^^
//This identifies the parameter
If # is not provided with the parameter name then it is added. Look at the following source code, (taken from here)
internal string ParameterNameFixed {
get {
string parameterName = ParameterName;
if ((0 < parameterName.Length) && ('#' != parameterName[0])) {
parameterName = "#" + parameterName;
}
Debug.Assert(parameterName.Length <= TdsEnums.MAX_PARAMETER_NAME_LENGTH, "parameter name too long");
return parameterName;
}
}
EDIT:
If you don't use # sign with the parameter then consider the following case.
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
conn.Open();
cmd.CommandText = "SELECT * from yourTable WHERE ID = ID";
cmd.Connection = conn;
cmd.Parameters.AddWithValue("ID", 1);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
}
}
The above will fetch all the records, since this will translate into SELECT * from yourTable WHERE 1=1, If you use # above for the parameter ID, you will get only the records against ID =1
OK, no offense to the posters before me but I will try to explain it to you as simple as possible, so even a 7 year old understands it. :)
From my experience '#' in .SQL is used when you are "just not making it clear what exact data type or exact name will be used". "Later" you are pointing out what the exact value of '#' is.
Like, say, someone has developed some huge .SQL query which contains, say, the name of every person who has received it.
SELECT column_name,column_name FROM table_name WHERE column_name = #YOURNAME;
#YOURNAME = 'John Doe';
So, in this case, it's easier for everyone to just write their name at #YOURNAME and it will automatically convert the query to (upon launch):
SELECT column_name,column_name FROM table_name WHERE column_name = 'John Doe';
P.S: I am sorry for my syntax errors and incorrect terminology but I am sure you should have understood it by now. :)
Variables and parameters in SQL Server are preceded by the # character.
Example:
create procedure Something
#Id int,
#Name varchar(100)
as
...
When you create parameter objects in the C# code to communicate with the database, you also specify parameter names with the # character.
(There is an undocumented feature in the SqlParameter object, which adds the # to the parameter name if you don't specify it.)

i'm lost: what is wrong with this ado.net code?

well, the question is clear i hope, the code is this:
string sql = "delete from #tabelnaam";
SqlCommand sc = new SqlCommand();
sc.Connection = getConnection();
sc.CommandType = CommandType.Text;
sc.CommandText = sql;
SqlParameter param = new SqlParameter();
param.Direction = ParameterDirection.Input;
param.ParameterName = "#tabelnaam";
param.Value = tableName;
sc.Parameters.Add(param);
OpenConnection(sc);
sc.ExecuteScalar();
tableName is supplied to this function.
I get the exception:
Must declare the table variable #tabelnaam
IIRC, you cant use a substitute the table name for a parameter.
Rather build the SQL string containing the correct table name.
Make to changes
rather than using paramter use this
string sql = string.format( "delete from {0}",tableName);
make use of executenonquery intead of ExecuteScalar
sc.ExecuteNonQuery();
As mentioned by others, you can't parameterise the table name.
However, as you rightly mention in comments on other answers, using simple string manipulation potentialy introduces a SQL injection risk:
If your table name input is fro an untrusted source, such as user input, then using this:
string sql = string.format( "DELETE FROM {0}",tableName);
leaves you open to the table name "myTable; DROP DATABASE MyDb" being inserted, to give you:
DELETE FROM myDb; DROP DATABASE MyDB
The way round this is to delimit the table name doing something such as this:
string sql = string.format("DELETE FROM dbo.[{0}]", tableName);
in combination with checking that the input does not contain either '[' or ']'; you should probably check it also doesn't contain any other characters that can't be used as a table name, such as period and quotes.
I dont think you can parameterize the table name. From what I have read you can do it via Dynamic sql and calling sp_ExecuteSQL.
Your SQL is incorrect, you are deleting from a table variable yet you haven't defined that variable.
Update: as someone has pointed out, you are trying to dynamically build a query string but have inadvertantly used SQL parameters (these do not act as place holders for string literals).
More here:
Parameterise table name in .NET/SQL?
You cannot parameterise the table name, you have to inject it into the command text.
What you can and should do is protect yourself against SQL injection by delimiting the name thus:
public static string Delimit(string name) {
return "[" + name.Replace("]", "]]") + "]";
}
// Construct the command...
sc.CommandType = CommandType.Text;
sc.CommandText = "delete from " + Delimit(tableName);
sc.ExecuteNonQuery();
See here and here for more background info.

Categories