Full text search stored procedure error - c#

This is the error I am getting:
Syntax error near 'online' in the full-text search condition '""online"*" and "and*" and ""text"*"'.
This is my stored procedure:
ALTER PROCEDURE dbo.StoredProcedure1
(
#text varchar(1000)=null
)
AS
SET NOCOUNT ON
declare #whereclause varchar(1000)
SET #whereclause = #text
SELECT articles.ArticleID AS linkid,
articles.abstract as descriptiontext,
articles.title as title,
'article' as source,
articles.releasedate as lasteditdate
FROM articles
WHERE CONTAINS(title, #whereclause)
ORDER BY lasteditdate DESC, source ASC
This what i pass to SP:
string content = "\"online\" and \"text\"";
part of C# code:
using (SqlConnection cn = new SqlConnection(this.ConnectionString))
{
SqlCommand cmd = new SqlCommand("StoredProcedure1", cn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#text", SqlDbType.VarChar).Value = searchExpression;
cn.Open();
UPDATE:
Strings that i try and errors that i get:
content = "online text";
Syntax error near 'text' in the full-text search condition 'online text'.
content = "\"online\" and \"text\"";
Syntax error near 'online' in the full-text search condition '""online"*" and "and*" and ""text"*"'.
content = "\"online and text\"";
Syntax error near 'online*' in the full-text search condition '""online*" and "and*" and "text"*"'.

From msdn:
Specifies the text to search for in column_name and the conditions for a match.
is nvarchar. An implicit conversion occurs when another character data type is used as input.
Because "parameter sniffing" does not work across conversion, use nvarchar for better performance.
So i've changed everything to nvarchar:
cmd.Parameters.Add("#text", SqlDbType.NVarChar).Value = searchExpression;
declare #whereclause nvarchar(1000)

I think SQl uses % instead of *

Try this one in your c# code when adding parameter:
cmd.Parameters.Add("#text", searchExpression);

The problem is with the extra quotation marks.
Instead of this:
string content = "\"online\" and \"text\"";
try this:
string content = "online and text";
It will generate a correct condition:
'"online*" and "and*" and "text*"'
Also if accept user input and pass it directly into a query like this - you are really opening your application to SQL injection.

Not sure if it's significant, but your procedure is expecting varchar and your calling code is saying the parameter is SqlDbType.Char.
I'm quite fond of DeriveParameters :
SqlCommand cmd = new SqlCommand("StoredProcedure1", cn);
cmd.CommandType = CommandType.StoredProcedure;
cn.Open()
SqlCommandBuilder.DeriveParameters cmd;
cmd.Parameters("#text").Value = searchExpression;

I use this method to remove slashes and then pass the resulting char array to sp.
public static char[] RemoveBackslash(string value)
{
char[] c = value.ToCharArray();
return Array.FindAll(c, val => val != 39).ToArray();
}
string content = "'\"online\" and \"text\"'";
Sqlparam = new SqlParameter("#search", SqlDbType.NVarChar);
Sqlparam.Value = RemoveBackslash(content);
Sqlcomm.Parameters.Add(Sqlparam);

Related

Call to Stored Procedure not updating as expected

I have a mystery with a stored procedure that I'm calling from code behind(C#). I am baffled because I have added watchpoints my code on the C# side and everything seems to be having the values that they should be going into the call to the stored procedure however, the procedure runs without any errors that I can tell and yet my table doesn't get updated with the values that I feel they should.
The SP gets three values passed to it.
Record ID (#Record_ID), Column to update (#UpdColumn), and the value to place in that column (#UpdValue).
Here is my SP that I am calling:
ALTER PROCEDURE [dbo].[Single_Col_Update]
-- Add the parameters for the stored procedure here
#Record_ID INT,
#UpdColumn CHAR,
#UpdValue NVARCHAR
AS
BEGIN
SET NOCOUNT ON;
IF #UpdColumn = 'TicketNumber'
UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
SET TicketNumber = #UpdValue
WHERE RecID = #Record_ID;
IF #UpdColumn = 'TicketClosed'
UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
SET TicketClosed = #UpdValue
WHERE RecID = #Record_ID;
IF #UpdColumn = 'Notes'
UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
SET Notes = #UpdValue
WHERE RecID = #Record_ID;
IF #UpdColumn = 'Exception_ID'
UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
SET ExceptionID = #UpdValue
WHERE RecID = #Record_ID;
END
Here is the code segment calling the SP:
foreach (string record in recordnumber)
{
SqlConnection con = new SqlConnection("Data Source=MyDataSource");
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "Single_Col_Update";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Record_ID", Convert.ToInt32(record));
cmd.Parameters.AddWithValue("#UpdColumn", Session["UpdColumn"]);
cmd.Parameters.AddWithValue("#UpdValue", Session["UpdValue"]);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
Since all the variables are right, I'm not sure why this isn't updating. Hoping some of you may see an error here.
UPDATED 5/19/2017 1:40PM Central -
Steve,
I attempted to implement the call as you prescribed below. I only made to variations to what you provided:
'cmd.Parameters.Add("#UpdValue", SqlDbType.NVarChar, 1024);' // instead of 255 because the column I'm feeding there is an NVarChar(MAX) I will likely have to go back and modify this to be greater than 1024. There didn't appear to be a MAX value that I could put in there so for testing the 1024 will suffice.
omitted the 'transaction.Rollback();' // I kept red lining on the word 'transaction' and despite what I tried I couldn't get it to validate it.
Bottom line is that after implementing the code below the results were exactly the same as before. The code executed without reporting any errors either via the Consol.Write I added or through the VS 2017 IDE.
SqlTransaction transaction;
try
{
using (SqlConnection con = new SqlConnection("Data Source=MyDataSource"))
using (SqlCommand cmd = new SqlCommand("Single_Col_Update", con))
{
con.Open();
transaction = con.BeginTransaction();
cmd.Transaction = transaction;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Record_ID", SqlDbType.Int);
cmd.Parameters.Add("#UpdColumn", SqlDbType.NVarChar, 255);
cmd.Parameters.Add("#UpdValue", SqlDbType.NVarChar, 1024);
foreach (string record in recordnumber)
{
cmd.Parameters["#Record_ID"].Value = Convert.ToInt32(record);
cmd.Parameters["#UpdColumn"].Value = Session["UpdColumn"].ToString();
cmd.Parameters["#UpdValue"].Value = Session["UpdValue"].ToString();
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
So I'm still where I was, but I have taken notice of what you shared and I concur with all you stated. I hadn't noticed that I was opening and closing the connection there and was not aware of other things you had shared.
However the quandary remains!
Update 05/22/2017 10:45AM Central time:
I realized that I was trying to stuff NVarchar type into to a Varchar type in my stored procedure. Once corrected the modifications that I made based on Steve's feedback worked just fine. I haven't tried it but I'm assuming that what I had to begin with would have worked if the types had matched to begin with, but Steve's example is cleaner so I am not even going back to test the old way. Thanks again Steve!
The problem is in the declaration of this parameter
#UpdColumn CHAR,
in this way the Stored Procedure expects a SINGLE char, not a string.
Thus all the following if statements are false and nothing will be updated
Change it to
#UpdColumn NVARCHAR(255)
The same is true for the #UpdValue parameter. Again, only a single char is received by the stored procedure. Doesn't matter if you pass a whole string.
If you don't specify the size of the NVARCHAR or CHAR parameters the database engine will use only the first char of the passed value.
I want also to underline the comment above from Alex K. While it should not give you a lot of gain it is preferable to open the connection and create the command with the parameters outside the loop. Inside the loop just change the parameters values and execute the sp
SqlTransaction transaction;
try
{
using(SqlConnection con = new SqlConnection(.....))
using(SqlCommand cmd = new SqlCommand("Single_Col_Update", con))
{
con.Open();
transaction = con.BeginTransaction())
cmd.Transaction = transaction;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Record_ID", SqlDbType.Int);
cmd.Parameters.Add("#UpdColumn", SqlDbType.NVarChar, 255);
cmd.Parameters.Add("#UpdValue", SqlDbType.NVarChar, 255);
foreach (string record in recordnumber)
{
cmd.Parameters["#Record_ID"].Value = Convert.ToInt32(record));
cmd.Parameters["#UpdColumn"].Value = Session["UpdColumn"].ToString();
cmd.Parameters["#UpdValue"].Value = Session["UpdValue"].ToString();
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
}
catch(Exception ex)
{
// show a message to your users
transaction.Rollback();
}
I have also added all your loop inside a transaction to confirm all the inserts as a whole or reject all in case of errors.
CHAR should only be used when a column is a fixed length. When you use it with varying length strings, the results will be usually not what you expect because the parameter/column will be padded with spaces which is why your IF statements are failing.
Don't use the CHAR type for #UpdColumn. Use NVARCHAR instead for this column and also it's a good practice to specify a length for both this parameter and the UpdValue parameter in your stored procedure and then match this closely when calling the stored procedure from your C# code.

Insert SQL with parameters causes "Incorect syntax near the keyword 'values'"

I want to populate a table in mssql with the values entered by the user (the error comes from the NumericUpDown) and I'm using this code:
string cs= "Data Source=CODRINMA\\CODRINMA;Initial Catalog=BusManager; Trusted_Connection=True;";
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values ([#TipAutocar], [#Marca], [#Model], [#Nrlocuri]))";
try
{
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
SqlCommand cmd = new SqlCommand(insert, con);
cmd.Parameters.AddWithValue("#IDTipAutocar", txtID.Text);
cmd.Parameters.AddWithValue("#Marca", txtMarca.Text);
cmd.Parameters.AddWithValue("#Model", txtModel.Text);
cmd.Parameters.AddWithValue("#Nrlocuri", nmrLocuri.Value);
int valoare = cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show(valoare + "Tipul de autocar a fost adaugat cu succes!", "BusManager");
}
}
catch (Exception er) { MessageBox.Show(er.Message); }
But, when I press button to insert, I'm having the following error and I can't figure it out what's to do:
Incorect syntax near the keyword 'values'.
I'm missing a closing round parenthesis before values here:
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values ([#IDTipAutocar], [#Marca], [#Model], [#Nrlocuri]))";
You are not allowed to use [] around the parameters, otherwise it's not a parameter and you'll get an error f.e. "invalid columnname [#TipAutocar]".
You also name the parameter #TipAutocar but you add it as IDTipAutocar.
Also, always use the correct type, all the more if you use AddWithValue which infers the type from the value. So i guess that IDTipAutocar is an int, then parse it to one before:
cmd.Parameters.AddWithValue("#IDTipAutocar", int.Parse(txtID.Text));
As an aside, i'm always using a verbatim string literal. On that way i can format my sql query as i want, even with multiple lines. This should work as exptected:
string insert = #"INSERT INTO TipAutocar
( IDTipAutocar, Marca, Model, Nrlocuri )
VALUES
( #IDTipAutocar, #Marca, #Model, #Nrlocuri)";
Look at this bracket;
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri] values (#TipAutocar, [#Marca, #Model, #Nrlocuri))";
^^^
You close it at the end of your query, you should close it just before your VALUES part.
Change it to;
string insert = "INSERT INTO TipAutocar ([IDTipAutocar], [Marca], [Model], [Nrlocuri]) values (#TipAutocar, #Marca, #Model, #Nrlocuri)";
^^^ ^^^
You don't need are not allowed to use square brackets for your parameters by the way. Also use using statement to dispose your SqlCommand as well. And since you used this statement for your SqlConnection, you don't need to close it with con.Close() because this statement do that automaticaly.
Also you define your parameter name as #TipAutocar in your command but try to add parameter name as #IDTipAutocar which does not match. Change your parameter name like;
cmd.Parameters.AddWithValue("#TipAutocar", txtID.Text);
And don't use AddWithValue anymore. It may generate unexpected results. Use .Add() method overloads instead to specify your SqlDbType and parameter size.

How to pass Byte Array in a Query using C#?

I'm trying to insert bytes of byte array in the database. using following code.
String query = String.Format(#"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
('{0}','{1}',{2})",
insertedBy, docName, docBytes);
Cmd.CommandText = query;
Cmd.ExecuteNonQuery();
Following exception is occured:
An object or column name is missing or empty. For SELECT INTO
statements, verify each column has a name. For other statements, look
for empty alias names. Aliases defined as "" or [] are not allowed.
Change the alias to a valid name. Incorrect syntax near ''.
I'm not getting what the reason is.
Never use string concatenation or string functions to make parametrized queries.
Also, because (I suspect that) docBytes is a byte[], string concatenation will not have the results that you hope for.
Here is how I would do it:
private static void InsertDocument(SqlCommand cmd, int insertedBy, string docName, byte[] docBytes)
{
cmd.CommandText = #"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
(#insertedBy,#docName,#docBytes)";
cmd.Parameters.Add("insertedBy", SqlDbType.Int).Value = insertedBy;
// Note: consider using `nvarchar` instead of `varchar`;
cmd.Parameters.Add("docName", SqlDbType.VarChar, 100).Value = docName;
// Note: -1 maps to the nvarchar(max) length;
cmd.Parameters.Add("docBytes", SqlDbType.VarBinary, -1).Value = docBytes;
// The following call presupposes that the associated `SqlConnection` is open
cmd.ExecuteNonQuery();
}
If your insertedBy column is an int, you don't need to use single quotes with it. Because you are try to insert characters to your int typed column.
Just use it like;
string query = String.Format(#"INSERT INTO [Documents]
([InsertedBy], [DocumentName], [Document])
VALUES
({0},'{1}',{2})",
insertedBy, docName, docBytes);
But since we don't know your values, this is the only suggestion I have.

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.)

exception on inserting single quote in c#

I am facing problem that. when I insert single quote in text field. on insertion it give exception of incorrect syntax near that particular field. why is it? does single quote has special meaning to sqlserver?
what if user what to enter word like don't , it's, or sometime by mistake enter single quote in start then it give exception. is there any sol to handle this? if single quote has issue with sqlserver.. then how to deal it?
use SqlParameter instead of string concatenation
This kind of expressions is worst thing you can do in your code, because at first you will have problem with data type convertion, and second the doors of Sql Injection is opem for hackers
string someQuery = "Select * from SomeTbl Where SomeTbl.SomeColumn = '" + tbSomeBox.Text+ "'" ;
Instead of that just use this
string someQuery = "Select * from SomeTbl Where SomeTbl.SomeColumn = #param";
SqlCommand someCommand = new SqlCommand(someQuery, conn);
someCommand.AddParams("#param",tbSomeBox.Text);
...
Hope this helps
SQL Server strings are enclosed (typically) in single quotes, so a single quote within a string will result in an error if you don't escape it prior to it being INSERTed.
Single quotes simply need to be doubled up, so the string Will''s World would result in Will's World making it's way into the data.
You will need to escape single quotes in SQL statements.
For example:
'don''t'
In SqlServer, if you want to insert string with quotes, use quotes twice before and after the string. For example you want to insert 'Hello', so insert it like '''Hello''' provided the field you want to insert in has string datatype like varchar etc.
using (System.Data.SqlClient.SqlConnection con = new SqlConnection("YourConnection string")) {
con.Open();
SqlCommand cmd = new SqlCommand();
string expression = "(newsequentiali'd())";
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Your Stored Procedure";
cmd.Parameters.Add("Your Parameter Name",
SqlDbType.VarChar).Value = expression;
cmd.Connection = con;
using (IDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
}
}
}

Categories