SQL output procedure C# ExecuteNonQuery "parameter not supplied" [duplicate] - c#

This question already has answers here:
Stored procedure or function expects parameter which is not supplied
(7 answers)
Closed last year.
This question has not been already answered. Similar question "Stored procedure or function expects parameter which is not supplied" is a different question about how to code the request in C#. My issue is an SQL issue. I am getting an error
parameter not supplied
inconsistently. If I am executing a stored procedure from SSMS with the following script, it works fine with the expected output:
declare #p5 int
execute dbo.aspCreateQuote #customerID = 13,#itemList='text goes here',#quoteID = #p5 output;
select #p5
The following script (from SQL Server Profiler) executed by an app does not work:
declare #p5 int
set #p5=NULL
exec sp_executesql N'psa.dbo.aspCreateQuote',N'#customerID int,#itemList varchar(3774), #quoteID int output'
,#customerID=13
,#itemList='[xml block of text goes here]',
#quoteID=#p5 output
select #p5
It generates the error:
'aspCreateQuote' expects parameter '#customerID', which was not supplied.
Clearly the parameter is supplied and is not null, so what's wrong?
The second script is generated by C# / ASP.NET SqlCommand.ExecuteNonQuery method as revealed by SQL Server Profiler. If there is something wrong with the script, then how to get C# to generate the correct script?
Here is the procedure:
ALTER PROCEDURE [dbo].[aspCreateQuote]
#customerID int,
#itemList xml,
#quoteID int OUTPUT
AS
INSERT INTO Quotes (CustomerID, Items)
VALUES (#customerID, #itemList);
SET #quoteID = (SELECT MAX(QuoteID) FROM Quotes WHERE CustomerID = #customerID);
RETURN #quoteID
And here is the C#:
SqlCommand sp = new SqlCommand("dbo.aspCreateQuote", cnx);
SqlParameterCollection parameterSet = sp.Parameters;
SqlParameter param;
param = new SqlParameter("#customerID", SqlDbType.Int);
param.Value = Convert.ToInt32(cartID);
parameterSet.Add(param);
param = new SqlParameter("#itemList", SqlDbType.VarChar);
param.Value = string.IsNullOrEmpty(xmlItems) ? "" : xmlItems;
parameterSet.Add(param);
param = new SqlParameter("#quoteID", SqlDbType.Int);
param.Value = 0;
param.Direction = ParameterDirection.Output;
parameterSet.Add(param);
sp.ExecuteNonQuery();
quoteID = (Int32)sp.Parameters["#QuoteID"].Value;
Thank you for your help.

You need to list the parameters as part of the #stmt value because that needs to be the exact SQL you wish to execute e.g.
declare #p5 int;
set #p5 = null;
exec sp_executesql N'dbo.aspCreateQuote #customerID, #itemList, #quoteID'
, N'#customerID int, #itemList varchar(3774), #quoteID int output'
, #customerID=13
, #itemList='[xml block of text goes here]'
, #quoteID=#p5 output;
select #p5;
FYI, using the RETURN statement for returning user values is not its intended use. The RETURN statement is for returning a status of the stored procedure.

Related

JSON string output parameter from SQL Server stored procedure works in SSMS but produces empty value in C# client

In my stored procedure, I've declared an OUTPUT parameter called #Stats:
#Stats nvarchar(max) OUTPUT
At the end of my stored procedure, I assign the results of a JSON query to the output parameter:
SELECT #Stats = (SELECT * FROM JsonStats FOR JSON AUTO)
If I execute the stored procedure in SSMS, I get the JSON data back from #Stats as expected:
DECLARE #Param1 nvarchar(max) = '...'
DECLARE #Stats nvarchar(max)
EXEC MySP #Param1, #Stats OUTPUT
SELECT #Stats
However, when I execute the stored procedure from C# code, I get an empty string back:
SqlCommand cmd = new SqlCommand("MySP", conn)
{
CommandType = CommandType.StoredProcedure
};
var inputParam = new SqlParameter("#Param1", invoiceKeyListJson);
cmd.Parameters.Add(inputParam);
var outputParam = new SqlParameter("#Stats", SqlDbType.NVarChar, -1);
outputParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outputParam);
cmd.ExecuteNonQuery();
string statsJson = outputParam.Value.ToString();
After running the above code, statsJson is empty. The weird thing is, if I hard code the assignment of #Stats to an arbitrary string in the stored procedure, statsJson is assigned that value.
Why the inconsistency in results between SSMS and C#? What do I need to do to get the JSON data back in C#?
You have to set the size of your outputParam like so:
var outputParam = new SqlParameter("#Stats", SqlDbType.NVarChar, 100000)
I resolved this by changing
SELECT #Stats = (SELECT * FROM JsonStats FOR JSON AUTO)
to:
SELECT #Stats = CAST((SELECT * FROM JsonStats FOR JSON AUTO) AS nvarchar(max))
(explicitly casting to nvarchar(max)).

How to get list of values from SQL stored procedure using ExecuteSqlCommand

I am trying to get a list of values in a SQL table as output based on an input parameter using the following SQL stored procedure.
CREATE PROCEDURE GetFirstNames
#LastName nvarchar(128),
#FirstNames nvarchar(128) OUTPUT
AS
SET #FirstNames = (SELECT FirstName FROM NamesTable WHERE LastName = #LastName)
GO
I am using the following code to get the list of first names from the table.
SqlParameter lastNameParam = new SqlParameter("#LastName", "Smith");
SqlParameter firstNamesParameter = new SqlParameter("#FirstNames", SqlDbType.NVarChar, 128);
firstNamesParameter.Direction = ParameterDirection.Output;
string sql = String.Format("EXEC dbo.GetFirstNames {0}, {1};",
lastNameParam.ParameterName,
firstNamesParameter.ParameterName);
context.Database.ExecuteSqlCommand(sql, lastNameParam, firstNamesParameter);
When I call the ExecuteSqlCommand method I get the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
How I can resolve the query error so that I can get the list of first names?
How can I return this list and use it in my c# code?
I would really appreciate if someone can help me with this.
Thanks.
CREATE PROCEDURE GetFirstNames
#LastName nvarchar(128)
AS
SET NOCOUNT ON
SELECT FirstName FROM NamesTable WHERE LastName = #LastName
GO
Will fix the query portion and give you an enumerable result set. The rest is an exercise for the OP.

MS-SQL Stored Procedure doesn't work with empty params

I have a form with inputs 'name' and 'phone'.
When they have values, everything works: a record is inserted into the database using a stored procedure, spFoo:
String sp = "spFoo 'test name','test phone'";
OdbcCommand command = new OdbcCommand(sp, connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
Response.Write(command.ExecuteNonQuery().ToString());
Works on application
Works on Mgmt Studio
But when they don't have values I get -1 as a response in the application:
String sp = "spFoo '',''";
Does not work in application (-1)
Works on Mgmt Studio
I want the user to be able to create a record without any input.
Why does this work in management studio, but not on the application?
Update: I added defaults to the params in the stored procedure, it didn't work; I gave empty strings "NULL" as values in the code, still no luck. Is this a server setting or something that won't allow empty variables?
You'll need to remove the SET NOCOUNT ON; from your stored procedure.
From the documentation:
Stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set.
As others have pointed out you should parameterise your query too but the -1 is caused by NOCOUNT being ON.
Edit
I realise it's not what you're asking but to use a parameterised query with ODBC you need to use ?'s as ordinal place holders as per the documentation here. For example:
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
string sp = "{call spFoo (?, ?)}";
using (OdbcCommand command = new OdbcCommand(sp, connection))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
//the order here is important, the names are not!
command.Parameters.Add("#name", OdbcType.VarChar).Value = "test name";
command.Parameters.Add("#phone", OdbcType.VarChar).Value = "test phone";
Console.WriteLine(command.ExecuteNonQuery().ToString());
}
}
When you are calling a stored procedure from code, you should use the Parameters property on the command. Try this:
String sp = "spFoo";
command.Parameters.Add("#name", "test name");
command.Parameters.Add("#phone", "test phone");
As JimmyV said, you should use the command.Parameters.Add method to setup your parameters, passing in null whenever a parameter value is not specified. To address your comment about the error 'procedure or function 'spFoo' expects parameter '#name', which was not supplied', you'll also need to modify your stored procedure to use default values when a param is not supplied (e.g. null):
CREATE PROCEDURE MyStoredProcedure
#foo int = null
AS
BEGIN
...
END
Sorry for not adding this a comment on the above post. Not enough reputation!
You shouldn't be calling a stored procedure the way that you currently are. You should be using parameters. Your code is susceptible to SQL injection.
Never string concat user inputted values.
What you should have, is a stored procedure setup similarly:
CREATE PROCEDURE spFoo
#name varchar(50) = 'Jim', -- default
#phone varchar(50) = null -- optional
AS
BEGIN
SET NOCOUNT ON;
-- INSERT STATEMENT
END
GO
And then supply the parameters in the code:
string name = this.nameTextBox.Text;
string phone = this.phoneTextBox.Text;
if (string.IsNullOrWhiteSpace(name))
name = null;
if (string.IsNullOrWhiteSpace(phone))
phone = null;
SqlConnection connection = new SqlConnection(#"<connection string>");
using (SqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
// leave this as the stored procedure name only
command.CommandText = "spFoo";
// if name is null, then Jim gets passed (see stored procedure definition)
// if phone is null, then null gets passed (see stored procedure definition)
command.Parameters.AddWithValue("#name", name);
command.Parameters.AddWithValue("#phone", phone);
try
{
connection.Open();
int result = command.ExecuteNonQuery();
Console.WriteLine(result);
}
finally
{
if (connection.State != ConnectionState.Closed)
connection.Close();
}
}
I'm not sure why you used the Odbc namespace objects since it sounds like you are using MS-SQL. You should be using objects from the System.Data.SqlClient namespace.
The answer to your actual question would most likely involve executing a script (not a stored procedure) similar to:
DECLARE #RC int
DECLARE #name varchar(50)
DECLARE #phone varchar(50)
-- TODO: Set parameter values here.
EXECUTE #RC = spFoo
#name,
#phone
GO
Which is not recommended.

Return multiple values from Stored Procedure in C#

I need to return 2 values from stored procedure in my application. Below is the code snippet in my application. I need to get the values of SureveyID & InputID below after the respective insert statements.
int surveyId = 0;
int inputId = 0;
SqlDataManager manager = new SqlDataManager();
manager.AddParameter("#Name", surveyInstance.SurveyName);
manager.AddParameter("#Type", surveyInstance.SurveyType);
manager.AddParameter("#UserId", surveyInstance.UserId);
manager.AddParameter("#InputType", surveyInstance.InputType);
manager.AddParameter("#DisplayName", surveyInstance.DisplayName);
manager.AddOutputParameter("#SurveyID",System.Data.DbType.Int32,surveyId);
manager.AddOutputParameter("#InputID", System.Data.DbType.Int32,inputId);
manager.ExecuteNonQuery("pr_CreateSurvey");
AddParameter & AddOutputParameter is custom method as below
public void AddParameter(string parameterName, DbType parameterType, object parameterValue)
{
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = parameterName;
parameter.DbType = parameterType;
parameter.Value = parameterValue;
parameters.Add(parameter);
}
public void AddOutputParameter(string parameterName, DbType parameterType, object parameterValue)
{
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = parameterName;
parameter.DbType = parameterType;
parameter.Value = parameterValue;
parameter.Direction = ParameterDirection.Output;
parameters.Add(parameter);
}
Below is code snippet from stored procedure
ALTER PROCEDURE [dbo].[pr_CreateSurvey]
-- Add the parameters for the stored procedure here
#Name varchar(50),#Type varchar(50),#UserId varchar(50),#InputType varchar(50),#DisplayName varchar(50),
#SurveyID int OUTPUT,#InputID int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Insert into surveys(name,user_id,display_name,type) values(#Name,#UserId,#DisplayName,#Type)
SET #SurveyID = SCOPE_IDENTITY()
Insert into input_types(name) values (#InputType)
SET #InputID = SCOPE_IDENTITY()
END
The insert statements are working fine but I am not getting back any value in my application. Its 0.
I tried returning 1 value(SurveyID) by using below statement but still not getting correct value. Its returning -1 everytime.
surveyId = manager.ExecuteNonQuery("pr_CreateSurvey");
I tried a lot but no luck. Please advise.
find the values of the output parameters in the Parameters collection of your SqlCommand ... like
mySqlCommand.Parameters["#SurveyID"].Value
after you executed
mySqlCommand.ExecuteNonQuery();
Keep a variable of your ouput parameters around and check the .Value afterwards. The ouput gets written to the parameter, but due to boxing, it does not get written to your int. Basically, your int was copied into the parameter and your original variables do not change.
ExecuteNonQuery returns the number of rows affected, not anything else.
I've never used output parameters in my stored procedures for this. What I usually do is select out the values I want to return.
So after you do this:
SET #SurveyID = SCOPE_IDENTITY()
SET #InputID = SCOPE_IDENTITY()
I will do this
select #SurveyID as SurveyID,#InputID as InputID
Of course I'll declare those variables within the stored procedure and not as OUTPUT
This should give you what you want. If it's the correct way? Not sure. But it sure as hell works and is easy ;)

Entity Framework: how do I run a stored procedure and return a value?

Is it possible to execute a stored procedure using the Entity Framework, passing in variables and returning data along with a return value?
Please do not leave any code about function mappings with Entity Framework.
I have tried this and I keep getting the same damn error:
Procedure or function 'usp_BusinessUser_Search' expects parameter
'#TotalRecords', which was not supplied.
Here's my code:
SqlParameter Business = new SqlParameter("Business", Search.Term);
SqlParameter Location = new SqlParameter("Location", Search.Location);
SqlParameter PageNumber = new SqlParameter("PageNumber", Search.CurrentPage);
SqlParameter RecordsPerPage = new SqlParameter("RecordsPerPage", Search.RecordsPerPage);
SqlParameter TotalRecords = new SqlParameter("TotalRecords", 0);
SqlParameter parm = new SqlParameter()
{
ParameterName = "#TotalRecords",
Value = 0,
SqlDbType = SqlDbType.Int,
Direction = System.Data.ParameterDirection.Output
};
var List = db.ExecuteStoreQuery<ENT_SearchBusinessResult>("exec usp_BusinessUser_Search",Business,Location,PageNumber,RecordsPerPage,parm);
Does anyone have any idea what is causing this?
Thanks
EDIT:
Stored procedure code:
ALTER PROCEDURE [dbo].[usp_BusinessUser_Search] ( #Business nVarChar(255) = NULL
, #Location nVarChar(255) = NULL
, #PageNumber Int = 1
, #RecordsPerPage Int = 10
, #TotalRecords Int OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX)
, #CacheTable SYSNAME
, #TotalRows Int
, #Category VarChar(255)
, #BusinessCategory Int
, #TownCounty VarChar(50)
, #PcodeTownCounty VarChar(50)
INSERT Voucher_SearchHistory (Keyword, Location)
SELECT NULLIF(#Business,''), NULLIF(#Location,'')
This might help:
http://blogs.msdn.com/b/diego/archive/2012/01/10/how-to-execute-stored-procedures-sqlquery-in-the-dbcontext-api.aspx
You are not passing TotalRecords Sql Parameter in Excecute
var List = db.ExecuteStoreQuery<ENT_SearchBusinessResult>(
"exec usp_BusinessUser_Search",Business,
Location,PageNumber,RecordsPerPage,parm);
You can now use the following extension method, ExecuteSqlCommandWithReturn, that takes care of all of the work for you!
https://gist.github.com/copernicus365/7037320
string sql = "EXEC sp_CoolProc #SomeParam, #AnotherParam";
int returnValue;
int val = db.ExecuteSqlCommandWithReturn(sql, out returnValue, someParam, anotherParam);
The key to the solution was by Jieyang Hu here, which is this (though note that all of the following is fully handled by the aforementioned extension method): Just as you can do in a SQL prompt, you just set the result of the executed procedure to a SQL variable (in this case which is sent in as a parameter), like this:
EXEC #ReturnVal = sp_MyCoolProc;
This code adds the fragment #ReturnVal = after the first EXEC (followed by whitespace) it finds, and adds to the SqlParameters (or creates SqlParamters if there were none) a ReturnVal parameter, though the caller will never see these.
The parameter name should not contain #:
SqlParameter parm = new SqlParameter()
{
ParameterName = "TotalRecords",
Value = 0,
SqlDbType = SqlDbType.Int,
Direction = System.Data.ParameterDirection.Output
};
If you just added that parameter ('#TotalRecords) recently
I am going to guess that you just need to update your function import definition in your edmx model.

Categories