I need to know, if I am writing the stored procedure correctly and If the C# code for executing is correct. for some reason the error being returned as is Incorrect syntax near 'c16b'. Old Error
The new error now is: Procedure or function 'sptimeupdate' expects parameter '#date', which was not supplied.
the nvarchar string for validating and updating in the column by ClientID is 3fc8ffa1-c16b-4d7b-9e55-1e88dfe15277, but the part in bold is only showing in the debug test intel sense in error handling
ALTER PROCEDURE sptimeupdate
#id nvarchar(50),
#date datetime
AS
BEGIN
SET NOCOUNT ON;
UPDATE ClientTable
SET Today_Date=(#date)
WHERE ClientID=(#id)
END
//--------------above stored procedure--------------------------------
//--------------Executing the stored procedure in C#
IEnumerable<XElement> searchClientID =
from clientid in main.XPathSelectElements("Network/ClientID")
where (string)clientid.Attribute("id") == IntializedPorts[i].ToString()
select clientid;
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count(); up++)
{
//Update the current time in the clientid tble.
//Renames the table copy for groups
try
{
string[] Clientid; //client id array
Clientid = new string[IntializedPorts.Count()]; //Intialization of the array
Clientid[up] = clientid.ToString();
DateTime td = Convert.ToDateTime(toolDate.Text); //Just added a datetime object withdate
SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True");
//EXECUTE THE STORED PROCEDURE sptimedate
// string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
string UpdateCommand = "sptimeupdate" + "'" + Clientid[up].ToString() + "'" + "'" +td.ToString()+ "'"; //this is the new UpdateCommand string as to pass parameters to stored procedure
SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString);
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
sqlConnectionCmdString.Close();
}
catch(DataException ex)
{ MessageBox.Show("Failed to UpdateCurrentTime","DataError",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
}
When you call a stored procedure from code you need to create a command with its command type set to StoredProcedure, otherwise the engine tries to use your command text as it was an sql text like SELECT INSERT etc... But the mose important thing is that you need to pass the parameters required by the stored procedure in the Parameters collection of the command
So this could be the code to replace the actual one
string UpdateCommand = "sptimeupdate";
using(SqlConnection sqlConnectionCmdString = new SqlConnection(......))
using(SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString))
{
DateTime td = Convert.ToDateTime(toolDate.Text);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar).Value = Clientid[up].ToString();
sqlRenameCommand.Parameters.Add("#date", SqlDbType.DateTime).Value = td;
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
}
Notice two things. The using statement is the best practice to follow when you create a connection to ensure the correct closing and disposing of the connection, second, the parameter for the DateTime expected by the sp should be passed as a DateTime not as a string- Of course this means that you should be certain that the content of toolDate is convertible to a DateTime value.
Your error is originating from this line of code:
string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
There you are just concatenating the Clientid[up].ToString() as a string into the other string, same with the toolDate.Text, both without and sql markup.
Your resulting SQL query would look like this (assuming toolDate.Text is '2014-10-23'):
sptimeupdate3fc8ffa1-c16b-4d7b-9e55-1e88dfe152772014-10-23
which as you can see is not a proper SQL command.
You should always use parametrized command statements when calling simple SQL commands.
However in your case, you are actually calling a stored procedure.
So change your code to handle it like a stored procedure, example below.
// Create the connection object once
using (SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True"))
{
// Same with the SqlCommand object and adding the parameters once also
SqlCommand sqlRenameCommand = new SqlCommand("sptimeupdate", sqlConnectionCmdString);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar);
sqlRenameCommand.Parameters.Add("#datetime", SqlDbType.DateTime);
// Open the connection once only
sqlConnectionCmdString.Open();
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count; up++)
{
try
{
// The below three lines seem redundant.
// Clientid[up] will be equal to clientid after it all, so just use clientid
//string[] Clientid;
//Clientid = new string[IntializedPorts.Count];
//Clientid[up] = clientid.ToString();
sqlRenameCommand.Parameters["#id"].Value = clientid;
sqlRenameCommand.Parameters["#datetime"].Value = toolDate.Text;
sqlRenameCommand.ExecuteNonQuery();
}
// Might want to move this try..catch outside the two loops,
// otherwise you will get this message each time an error happens
// which might be alot, depending on the side of searchClientID
catch (SqlException)
{
MessageBox.Show("Failed to UpdateCurrentTime", "DataError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
NOTE:
Please read the comments inside the code above for additional advice and suggestions.
Recreating a SqlConnection and SqlCommand for each iteration will have a performance impact on your application. So rather create them once and reuse them until you are done.
Further reading can be done here:
SqlCommand (There are nice examples at the bottom of that page)
dotnetperls version of SqlCommand
P.S. your sql procedure's code looks fine, you could remove the SET NOTCOUNT ON since that does not really do much in this scenario
Related
After reading an interesting article online : Calling DB2 stored procedures from .NET applications
I'd like to share an issue recently encountered with a derived code :
DateTime transa_date = DateTime.ParseExact(trandate, "yyyy-MM-dd",
CultureInfo.InvariantCulture);
DB2Connection conn = new DB2Connection(MyDb2ConnectionString);
conn.Open();
try
{
// MyDb2Connection.Open();
// conn.Open();
// assume a DB2Connection conn
DB2Transaction trans = conn.BeginTransaction();
cmd = conn.CreateCommand();
procName = "MYTBLSCHEMA.TEST";
procCall = "CALL MYTBLSCHEMA.TEST(#NAME, #ADDRESS_LINE, #REGNUM, #TRANSA)";
cmd.Transaction = trans;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = procCall;
// Register input-output and output parameters for the DB2Command
cmd.Parameters.Add( new DB2Parameter("#NAME", name)); #of string type
cmd.Parameters.Add( new DB2Parameter("#ADDRESS_LINE", adr)); #of string type
cmd.Parameters.Add( new DB2Parameter("#REGNUM", reg)); #of string type
cmd.Parameters.Add( new DB2Parameter("#TRANSA", transa_date)); #of date type (in DB2 table)
// Call the stored procedure
Console.WriteLine(" Call stored procedure named " + procName);
cmd.ExecuteNonQuery();
}
The above code neither generates an exception at cmd.ExecuteNonQuery() nor inserts the (expected) row into the table.
Hence, a Hope to understand through this post the rationale underlying such phenomenon.
Thanks.
N.B: Executing (manually)
CALL MYTBLSCHEMA.TEST('test', 'test_address_', 'test_num', 2021-01-01)
from the IDE does work (e.g. insert the row into the table).
DB2 version: 11.5.6.0.00000.008
I'd either remove this line:
DB2Transaction trans = conn.BeginTransaction();
Or I'd add this line at the end of the try:
trans.Commit();
As to which you'd choose; as it's a single stored procedure, unless there's some internal overriding concern within the sproc that makes sense to have a transaction to be started outside it cover it, I'd remove it. If you have, or plan to have multiple operations that must either all-succeed or all-fail, then I'd keep it/commit it..
I'm working on WCF project. I am trying to insert multiple records into my SQL Server database from an array.
when calling the service, I get an exception :"Procedure or function has too many arguments specified", while my arguments in my function are in confirmity with those declared in my stored procedure :
Here is my function in WCF :
public static string SetGaranties( List<int> CODE_GARANTIES, string NUMERO_POLICE, string CODE_BRANCHE, int CODE_SOUS_BRANCHE)
{
string MSG_ACQUITEMENT = string.Empty;
DbCommand com = GenericData.CreateCommand(GenericData.carte_CarteVie_dbProviderName, GenericData.Carte_CarteVie_dbConnectionString);
com.CommandText = "SetGaranties";
com.Parameters.Clear();
foreach (int CODE_GARANTIE in CODE_GARANTIES)
{
com.Connection.Open();
SqlParameter NUMERO_POLICE_Param = new SqlParameter("#NUMERO_POLICE", NUMERO_POLICE);
com.Parameters.Add(NUMERO_POLICE_Param);
SqlParameter CODE_BRANCHE_Param = new SqlParameter("#CODE_BRANCHE", CODE_BRANCHE);
com.Parameters.Add(CODE_BRANCHE_Param);
SqlParameter CODE_SOUS_BRANCHE_Param = new SqlParameter("#CODE_SOUS_BRANCHE", CODE_SOUS_BRANCHE);
com.Parameters.Add(CODE_SOUS_BRANCHE_Param);
SqlParameter CODE_POSTALE_Param = new SqlParameter("#CODE_GARANTIE", CODE_GARANTIE);
com.Parameters.Add(CODE_POSTALE_Param);
DbDataReader reader = com.ExecuteReader();
com.Connection.Close();
}
and here is my Stored procedure :
ALTER PROCEDURE [dbo].[SetGaranties]
#NUMERO_POLICE varchar(12),
#CODE_BRANCHE varchar(1),
#CODE_SOUS_BRANCHE int,
#CODE_GARANTIE int
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.MVT_GARANTIES VALUES(
#NUMERO_POLICE,
#CODE_BRANCHE,
#CODE_SOUS_BRANCHE,
#CODE_GARANTIE
);
END
Does anybody know how to fix this?
Build the parameters outside the loop just once, set the invariant values outside the loop and inside the loop just set only the one value that changes at each loop
public static string SetGaranties( List<int> CODE_GARANTIES, string NUMERO_POLICE, string CODE_BRANCHE, int CODE_SOUS_BRANCHE)
{
string MSG_ACQUITEMENT = string.Empty;
DbCommand com = GenericData.CreateCommand(GenericData.carte_CarteVie_dbProviderName, GenericData.Carte_CarteVie_dbConnectionString);
com.CommandText = "SetGaranties";
com.CommandType = CommandType.StoredProcedure;
// These parameter's values don't change, set it once
com.Parameters.Add("#NUMERO_POLICE", SqlDbType.VarChar).Value = NUMERO_POLICE;
com.Parameters.Add("#CODE_BRANCHE",SqlDbType.VarChar).Value = CODE_BRANCHE;
com.Parameters.Add("#CODE_SOUS_BRANCHE", SqlDbType.Int).Value = CODE_SOUS_BRANCHE;
// This parameter's value changes inside the loop
com.Parameters.Add("#CODE_GARANTIE",SqlDbType.Int);
com.Connection.Open();
foreach (int CODE_GARANTIE in CODE_GARANTIES)
{
com.Parameters["#CODE_GARANTIE"].Value = CODE_GARANTIE;
com.ExecuteNonQuery();
}
com.Connection.Close();
}
Other things to say:
You are using a global connection object, this usually is a very bad
idea. ADO.NET implements connection pooling and this means that you
should create your connection when you need it and destroy it
afterwards.
ExecuteNonQuery should be used when you INSERT/UPDATE/DELETE records.
No need to build an SqlDataReader when you don't have anything to
read back.
A Stored Procedure is executed only if you set the CommandType to
StoredProcedure otherwise you get a syntax error because the
CommandText is not a valid Sql Statement
This:
com.Parameters.Clear();
Should be inside your loop. With the current code the first iteration should have the correct number of parameters. But subsequent iterations will have too many because the the param list isn't being cleared.
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.
Stored procedure executes fine if executed in SQL Server Management Studio.
In C# (Winforms) I have the following code:
InsertWarning.Parameters.AddWithValue("#idUser", userIDAuth);
InsertWarning.Parameters.AddWithValue("#idPass", idPass);
if (Privileged)
MessageWarning += " gave you privileged access to note " + Description;
else
MessageWarning += " gave you access to note " + Description;
InsertWarning.Parameters.AddWithValue("#Message", MessageWarning);
InsertWarning.ExecuteNonQuery();
InsertWarning.Parameters.Clear();
When ExecuteNonQuery() runs it stops saying the #idUser has no value.
Stored procedure in C#:
SqlCommand InsertWarning = new SqlCommand("_spInsertWarnings", TeamPWSecureBD);
InsertAuths.CommandType = CommandType.StoredProcedure;
Stored procedure in SQL:
[dbo].[_spInsertWarnings]
#idUser int, #idPass int, #Message nvarchar(MAX)
AS
INSERT INTO Warnings
VALUES(#idUser, #idPass, #Message)
using (SqlConnection con = new SqlConnection(dc.Con))
{
using (SqlCommand cmd = new SqlCommand("_spInsertwarnings", con))
{
cmd.CommandType = CommandType.StoredProcedure;
//Please Make SqlDataType as per your Sql ColumnType
cmd.Parameters.Add("#idUser", SqlDbType.VarChar).Value = userIDAuth;
cmd.Parameters.Add("#idPass", SqlDbType.VarChar).Value = idPass;
con.Open();
cmd.ExecuteNonQuery();
}
}
The question in this post looks similar to yours:
Stored procedure or function expects parameter which was not supplied
Have you tried using the .Parameters.Add("fieldname", type, value) instead? I'm wondering if even though you are seeing the value 8 in a debug session, it's not being recognized when you do a stored procedure call.
Thinking about this again, my guess is you're missing a different parameter than #idUser, and that parameter does not have a default value assigned. Sometimes SQL Server reports the wrong name back for a parameter missing a value.
Look at your proc header and confirm that you're passing all the required parameters that the proc expects, or that you have sensible defaults assigned for the ones you don't always want to pass.
I guess this might work, i have posted the code from where you are adding.
InsertWarning.Parameters.Add("#idUser", SqlDbType.Int);
InsertWarning.Parameters["#idUser"].Value = userIDAuth;
InsertWarning.Parameters.AddWithValue("#idPass", idPass);
try
{
connection.Open();
InsertWarning.ExecuteNonQuery()
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I'm running a query from a web form to update records. Since I'm just learning about C#, I'm using a command string as opposed to a stored procedure.
My update method is as follows:
public void updateOne()
{
string commandText = "update INVOICE SET <Redacted> = #<Redacted>,
Supplier = #Sup, SupplierName = #SupN, NetTotal = #Net,
VATTotal = #VAT, InvoiceDate = #InvDt "
<needed a line break here, which is why I split the string again>
+ "WHERE K_INVOICE = #K_INV";
using (SqlConnection dbConnection = new SqlConnection
(conParams.connectionString))
{
SqlCommand cmd = new SqlCommand(commandText, dbConnection);
cmd.Parameters.Add("#K_INV", SqlDbType.Int);
cmd.Parameters["#K_INV"].Value = #K_INV;
cmd.Parameters.AddWithValue("#<Redacted>", #<Redacted>.ToString());
cmd.Parameters.AddWithValue("#Sup", #Sup.ToString());
cmd.Parameters.AddWithValue("#SupN", #SupN.ToString());
cmd.Parameters.AddWithValue("#Net", #Net.ToString());
cmd.Parameters.AddWithValue("VAT", #VAT.ToString());
cmd.Parameters.AddWithValue("#InvDt", #InvDt.ToString());
try
{
dbConnection.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
errorString = e.Message.ToString();
}
}
}
Catch stalls on an SQL error (Incorrect syntax near SET), and I have an idea that the issue occurs because I convert the parameters to strings. The first parameter is an Int, which should be OK.
If this is the case, what should I convert the parameters to? If not, what on earth is wrong?
Try to add a # before the string to escape the breaklines, for sample:
string commandText = #"update INVOICE SET [Redacted] = #Redacted,
Supplier = #Sup, SupplierName = #SupN, NetTotal = #Net,
VATTotal = #VAT, InvoiceDate = #InvDt "
+ "WHERE K_INVOICE = #K_INV";
In parameterName argument you can add the # but the value not, just the variable, for sample
cmd.Parameters.AddWithValue("#Redacted", redacted.ToString());
Try to execute this query in the databse with some values to check if everything is correct. You could use [brackets] in the table name and column names if you have a reserved word.
I would recommend you read this blog article on the dangers of .AddWithValue():
Can we stop using AddWithValue already?
Instead of
cmd.Parameters.AddWithValue("#Sup", #Sup.ToString());
you should use
cmd.Parameters.Add("#Sup", SqlDbType.VarChar, 50).Value = ...(provide value here)..;
(is your variable in C# really called #SupN ?? Rather unusual and confusing....)
I would recommend to always define an explicit length for any string parameters you define