I have a stored procedure in SQL Server :
CREATE PROCEDURE [dbo].[GET_AVAILABLE_PLACES]
-- Add the parameters for the stored procedure here
#eventGuid uniqueidentifier,
#placeGuid uniqueidentifier,
#dateGuid dateTime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #ReservedPlaces int;
DECLARE #TotalPlaces int;
SELECT #ReservedPlaces = RESERVED_PLACES FROM dbo.EVENT_DATE_PLACE
WHERE EVENT_GUID = #eventGuid
and DATE_BEGIN = #dateGuid
and PLACE_GUID = #placeGuid
SELECT #TotalPlaces = NUMBER_PLACES FROM dbo.PLACES
WHERE GUID = #placeGuid
RETURN #TotalPlaces - #ReservedPlaces;
END
But I can not seem to read the result returned
private int SelectByStoredProcedureGetAvailablePlaces(string entryParam1, string entryParam2, DateTime entryParam3)
{
int results;
//PlanningElement plan = GetPlanningElement(entryParam1, entryParam2, entryParam3.ToString(), "31/12/2012 00:00:00", "150");
using (SqlConnection sqlConnection = new SqlConnection(_connectionString))
{
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = "GET_AVAILABLE_PLACES";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("eventGuid", entryParam1);
sqlCommand.Parameters.AddWithValue("placeGuid", entryParam2);
sqlCommand.Parameters.AddWithValue("dateGuid", entryParam3);
sqlConnection.Open();
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
results = sqlDataReader.GetInt32(0);
sqlConnection.Close();
}
return results;
}
What is the problem ?
Thanks
The GetInt32 method will read from a selected table output. You want a return value, so you can change the code to be
SqlParameter returnValueParam = sqlcomm.Parameters.Add("#ReturnValue", SqlDbType.Int);
returnValueParam.Direction = ParameterDirection.ReturnValue;
sqlCommand.Parameters.Add(returnValueParam);
...
sqlCommand.ExecuteNonQuery();
result = returnValueParam.Value;
You can alter your stored procedure, replace
RETURN #TotalPlaces - #ReservedPlaces;
By:
SELECT (#TotalPlaces - #ReservedPlaces) AS [AvailablePlaces]
RETURN;
Your can also get a return value from your stored procedure, but that requires some more modifications. See this question for more information.
That particular type of return value must be read by using an additional parameter in the SqlCommand.Parameters collection with direction of System.Data.ParameterDirection.ReturnValue
To read it as you are attempting, your SQL procedure would need to do:
SELECT #TotalPlaces - #ReservedPlaces As MyResult
Then the result will be returned as a resultset instead of a return value.
So my stored procedure must be as this ?
CREATE PROCEDURE [dbo].[GET_AVAILABLE_PLACES]
-- Add the parameters for the stored procedure here
#eventGuid uniqueidentifier,
#placeGuid uniqueidentifier,
#dateGuid dateTime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #ReservedPlaces int;
DECLARE #TotalPlaces int;
SELECT #ReservedPlaces = RESERVED_PLACES FROM dbo.EVENT_DATE_PLACE
WHERE EVENT_GUID = #eventGuid
and DATE_BEGIN = #dateGuid
and PLACE_GUID = #placeGuid
SELECT #TotalPlaces = NUMBER_PLACES FROM dbo.PLACES
WHERE GUID = #placeGuid
SELECT #TotalPlaces - #ReservedPlaces As ReturnValue;
END
And my function as this ?
private int SelectByStoredProcedureGetAvailablePlaces(string entryParam1, string entryParam2, DateTime entryParam3)
{
int results;
//PlanningElement plan = GetPlanningElement(entryParam1, entryParam2, entryParam3.ToString(), "31/12/2012 00:00:00", "150");
using (SqlConnection sqlConnection = new SqlConnection(_connectionString))
{
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = "GET_AVAILABLE_PLACES";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("eventGuid", entryParam1);
sqlCommand.Parameters.AddWithValue("placeGuid", entryParam2);
sqlCommand.Parameters.AddWithValue("dateGuid", entryParam3);
SqlParameter returnValueParam = sqlCommand.Parameters.Add("#ReturnValue", SqlDbType.Int);
returnValueParam.Direction = ParameterDirection.ReturnValue;
sqlCommand.Parameters.Add(returnValueParam);
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
result = returnValueParam.Value;
sqlConnection.Close();
}
return results;
}
Try this in yourth strored procedure.
CREATE PROCEDURE [dbo].[GET_AVAILABLE_PLACES]
-- Add the parameters for the stored procedure here
#eventGuid uniqueidentifier,
#placeGuid uniqueidentifier,
#dateGuid dateTime,
#ReservedPlaces int output,
#TotalPlaces 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
SELECT #ReservedPlaces = RESERVED_PLACES FROM dbo.EVENT_DATE_PLACE
WHERE EVENT_GUID = #eventGuid
and DATE_BEGIN = #dateGuid
and PLACE_GUID = #placeGuid
SELECT #TotalPlaces = NUMBER_PLACES FROM dbo.PLACES
WHERE GUID = #placeGuid
SELECT #TotalPlaces - #ReservedPlaces As ReturnValue;
END
And this in your programm
private int SelectByStoredProcedureGetAvailablePlaces(string entryParam1, string entryParam2, DateTime entryParam3)
{
int results;
//PlanningElement plan = GetPlanningElement(entryParam1, entryParam2, entryParam3.ToString(), "31/12/2012 00:00:00", "150");
using (SqlConnection sqlConnection = new SqlConnection(_connectionString))
{
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = "GET_AVAILABLE_PLACES";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("eventGuid", entryParam1);
sqlCommand.Parameters.AddWithValue("placeGuid", entryParam2);
sqlCommand.Parameters.AddWithValue("dateGuid", entryParam3);
SqlParameter returnValueParam = sqlCommand.Parameters.Add("#ReturnValue", SqlDbType.Int);
returnValueParam.Direction = ParameterDirection.Output;
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
result = returnValueParam.Value;
sqlConnection.Close();
}
return results;
Related
I am trying to return a single value to c# using the executescalar method.
When I execute the below stored procedure in SQL Server, the if..blocks are working fine but executescalar in c# always returns 0.
Please refer to the below code:
USE [xx]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[prcAddress]
#ID int,
#Name varchar(50),
#Designation varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #count as Integer -- To count records
Declare #Result int -- To return result
SELECT #Result=0
SELECT #count = (SELECT count(*) FROM dbo.Address)
IF #ID >0
BEGIN
--Update the current entry
SELECT #Result=1
END
ELSE IF #ID =0 AND #count=0
BEGIN
-----do something
SELECT #Result=2
END
ELSE IF #ID=0 AND #count>0
BEGIN
----do something
SELECT #Result=3
END
ELSE
BEGIN
SELECT #Result=4
END
SELECT #Result As Result
END
GO
SqlConnection sqlCon = new SqlConnection(ConnectionString);
SqlCommand sqlCom = new SqlCommand();
try
{
sqlCom = new SqlCommand("prcAddress", sqlCon);
sqlCom.CommandType = CommandType.StoredProcedure;
sqlCom.CommandTimeout = 15;
sqlCom.Connection = sqlCon;
foreach (KeyValuePair<Object, Object> parmater in parameters)
{
if (parmater.GetType() == typeof(DateTime))
{
sqlCom.Parameters.Add("#" + parmater.Key, SqlDbType.DateTime).Value = parmater.Value;
}
else
{
sqlCom.Parameters.AddWithValue("#" + parmater.Key, parmater.Value);
}
}
if (sqlCon.State != ConnectionState.Closed)
{
sqlCon.Close();
}
sqlCon.Open();
if (sqlCom.ExecuteScalar() != null)
{
result = sqlCom.ExecuteScalar().ToString();
}
else
{
result = "";
}
}
catch (SqlException sqlEx)
{
System.Web.HttpContext.Current.Response.Redirect("~/Error.aspx", false);
}
finally
{
sqlCon.Close();
sqlCom = null;
}
You're probably seeing the result of the first select, 'SELECT #Result=0'. Either comment out all the selects prior to the last select in your stored procedure or change it to a scalar function that returns the result.
If I pass call my stored procedure from T-SQL:
exec [dbo].[StoredProcedureName] '''Vijay'', ''Rana'', 1, 0'
in SQL Server Mgmt Studio, it works fine but when I call it from my application it gives me error
Unclosed quotation mark after the character string ''Vijay','Rana',1,0'.
I searched on the google and find this EXEC sp_executesql #FinalQuery but its not working for me
EDIT
I am calling it like
public virtual IDataReader ImportFirefighter(String query)
{
Database database = DatabaseFactory.CreateDatabase();
DbCommand command = database.GetStoredProcCommand("[StoreProcedureName]");
database.AddInParameter(command, "#query", DbType.String, query);
IDataReader reader = null;
try
{
reader = database.ExecuteReader(command);
}
catch (DbException ex)
{
throw new DataException(ex);
}
return reader;
}
EDIT My complete Store Procedure
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
--[dbo].[ImportIntoFirefighter] '''Vijay'',''Rana'',''AC'',''AC'',''VOL'',1,0,0,1,1,''NA'','''',''VOL'','''','''',0,'''','''',0,1,1,'''',0&''Vijay21'',''Rana2'',''AC'',''AC'',''VOL'',1,0,0,1,1,''NA'','''',''VOL'','''','''',0,'''','''',0,1,1,'''',0&''Vijay32'',''Rana3'',''AC'',''AC'',''VOL'',1,0,0,1,1,''NA'','''',''VOL'','''','''',0,'''','''',0,1,1,'''',0&''Vijay42'',''Rana4'',''AC'',''AC'',''VOL'',1,0,0,1,1,''NA'','''',''VOL'','''','''',0,'''','''',0,1,1,'''',0'
ALTER PROCEDURE [dbo].[ImportIntoFirefighter]
#query VARCHAR(MAX)
AS
BEGIN
DECLARE #TotalRecord int
DECLARE #loopcount int
DECLARE #TempQueryList TABLE
(
[ID] INT IDENTITY(1,1),
[VALUE] VARCHAR(1000)
)
DECLARE #Result TABLE
(
[iff_id] INT IDENTITY(1,1),
[last_name] VARCHAR(50),
[first_name] VARCHAR(50),
[email] VARCHAR(50),
[mobile_number] VARCHAR(50),
[error] VARCHAR(max)
)
insert into #TempQueryList (VALUE) (
SELECT SUBSTRING('&' + #query + '&', Number + 1,
CHARINDEX('&', '&' + #query + '&', Number + 1) - Number -1)AS VALUE
FROM master..spt_values
WHERE Type = 'P'
AND Number <= LEN('&' + #query + '&') - 1
AND SUBSTRING('&' + #query + '&', Number, 1) = '&' )
Set #TotalRecord = (select count(*) FROM #TempQueryList)
--select * from #TempQueryList
--Loop For Each Repeated Schedule
set #loopcount = 1
WHILE #loopcount <= #TotalRecord
BEGIN
Declare #SingleQuery varchar(1000)
select #SingleQuery = Value from #TempQueryList where id = #loopcount
BEGIN TRY
--print '[AddFirefighter] ' + #SingleQuery
--SELECT 1/0;
--execute (#SingleQuery)
declare #FinalQuery varchar(max)
-- Select #SingleQuery = LEFT(RIGHT(#SingleQuery, len(#SingleQuery)-1),len(#SingleQuery)-2)
set #FinalQuery = '[AddFirefighter] ' + #SingleQuery
print #FinalQuery
EXEC (#FinalQuery)
END TRY
BEGIN CATCH
insert into #Result (last_name,first_name,email,mobile_number,error) values ( '','','','',ERROR_MESSAGE() )
-- Execute the error retrieval routine.
END CATCH
--print #loopcount
SET #loopcount = #loopcount + 1
END
select * from #Result
--execute (#query)
END
Well ' is the delimiter so it seems to me your string becomes 'Vijay','Rana',1,0 I think you are mixing strings and numerics in the same "string" what you need to do is pass 'Vijay','Rana','1','0' (a string of strings) and then sort things out inside your procedure. To do this your passed string should be something like ' '' Vijay'',''Rana'',''1'',''0'' '. Depending on how you handle things inside your stored proc you may even need '' '''' Vijay'''',''''Rana'''',''''1'''',''''0'''' '' .Best create a simple proc which just returns the string as a test bed
If you are using c# and asp.net, you should set up your parameters in code rather then building a dynamic sql statement. If you already have the stored procedure setup then I'm not seeing a reason to call a dynamic sql statement and building out the parameters in a string.
Here is a example of a parameterized call to sql with a stored procedure.
http://msdn.microsoft.com/en-us/library/yy6y35y8(v=vs.110).aspx
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory";
command.CommandType = CommandType.StoredProcedure;
// Add the input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
If your stored procedure takes four parameters as it seems to based on your question, you can add the parameters to a SqlCommand and then execute the command.
//Build your command
SqlConnection conn = new SqlConnection(yourConnectionString);
SqlCommand cmd = new SqlCommand("stored_procedure_name", conn);
cmd.CommandType = CommandType.StoredProcedure;
//Define the parameters to pass to the stored procedure
cmd.Parameters.Add("#firstParameter", SqlDbType.NVarChar, 255);
cmd.Parameters.Add("#secondParameter", SqlDbType.NVarChar, 255);
cmd.Parameters.Add("#thridParameter", SqlDbType.Int);
cmd.Parameters.Add("#fourthParameter", SqlDbType.Int);
//Assign Values to the parameters
cmd.Parameters["#firstParameter"].Value = "Vijay";
cmd.Parameters["#secondParameter"].Value = "Rana";
cmd.Parameters["#thirdParameter"].Value = 1;
cmd.Parameters["#fourthParameter"].Value = 0;
//Execute the command
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
I'm attempting to retrieve an integer value from a single table, based on the string field username. I've tried it using a stored proc, and direct text. When I execute the stored proc, I get the proper return value; however, the proper result doesn't come through.
Here are both sets of code -
Direct text -
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = CUSER";
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
}
SQL query:
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#username VARCHAR(50)
AS
BEGIN
-- Declare the return variable here
DECLARE #USRole as int
-- Add the T-SQL statements to compute the return value here
SELECT #USRole = tblUser.USRole FROM tblUser WHERE USUsername = #username
-- Return the result of the function
RETURN #USRole
END
You are not referencing your parameter correctly. If you are adding a parameter named USUsername then in the command text you should use #USUsername:
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = #USUsername";
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch (Exception)
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
}
Your stored procedure will also need updating as the parameter name here should also match and you don't need the return variable.
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#USUsername VARCHAR(50)
AS
BEGIN
-- Add the T-SQL statements to compute the return value here
SELECT tblUser.USRole FROM tblUser WHERE USUsername = #USUsername
END
You should also look at using the "using" syntax to automatically close your database connections. See Scott Hanselman's example here - http://www.hanselman.com/blog/WhyTheUsingStatementIsBetterThanASharpStickInTheEyeAndASqlConnectionRefactoringExample.aspx
Instead of using the return value of the stored procedure (RETURN #USRole), send the results back using a Select statement (e.g. Select #USRole). What is going on is that the return value of a stored procedure isn't the same as what is used by ExecuteScalar. ExecuteScalar returns the first column and row of the output. The return value is different and must accessed using the specially named parameter #RETURN_VALUE or the special ParameterDirection.ReturnValue property.
A revised version of your procedure would look like:
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#USUsername VARCHAR(50)
AS
BEGIN
-- Add the T-SQL statements to compute the return value here
Select tblUser.USRole
FROM tblUser
WHERE USUsername = #USUsername
END
RETURN (Transact-SQL)
SqlCommand.ExecuteScalar Method
I dont know how you called your stored procedure, but theres a bug in the query that you posted:
"SELECT USRole FROM tblUser WHERE USUsername = CUSER"
should be replaced with
SQLCommand.Parameters.Add("#USUsername", SqlDbType.VarChar).Value = CUSER;
"SELECT USRole FROM tblUser WHERE USUsername = #USUsername"
You are currently not really making the parameter part of the query, but trying to find the value CUSER within the column
Use parameter correctly. And dont forget to close connection on finally statement.
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = #USUsername ";
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch (Exception)
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
finally { close connection here.. }
}
If you insist on using the return value you can do it by setting the Parameter direction and using ExecuteNonQuery
SqlParameter p = cmd.Parameters.Add("#USRole", SqlDbType.Int);
p.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int returnvalue = (int)cmd.Parameters["#USRole"].Value;
If you want to use ExecuteScalar then just change your proc to select the variable instead of Return
You should note that what you put in for the parameter name is arbitrary.
I have a stored procedure, which returns the unique identifier after insertion ##identity. I tried it in the server explorer and it works as expected #RETURN_VALUE = [identifier].
In my code I added a parameter called #RETURN_VALUE, with ReturnValue direction first, than any other parameters, but when I run my query with ExecuteNonQuery() that parameter remains empty. I don't know what I've done wrong.
Stored Procedure
ALTER PROCEDURE dbo.SetAuction
(
#auctionID int,
#itemID int,
#auctionType tinyint,
#reservationPrice int,
#maxPrice int,
#auctionEnd datetime,
#auctionStart datetime,
#auctionTTL tinyint,
#itemName nchar(50),
#itemDescription nvarchar(MAX),
#categoryID tinyint,
#categoryName nchar(50)
) AS
IF #auctionID <> 0
BEGIN
BEGIN TRAN T1
UPDATE Auction
SET AuctionType = #auctionType,
ReservationPrice = #reservationPrice,
MaxPrice = #maxPrice,
AuctionEnd = #auctionEnd,
AuctionStart = #auctionStart,
AuctionTTL = #auctionTTL
WHERE AuctionID = #auctionID;
UPDATE Item
SET
ItemName = #itemName,
ItemDescription = #itemDescription
WHERE
ItemID = (SELECT ItemID FROM Auction WHERE AuctionID = #auctionID);
COMMIT TRAN T1
RETURN #auctionID
END
ELSE
BEGIN
BEGIN TRAN T1
INSERT INTO Item(ItemName, ItemDescription, CategoryID)
VALUES(#itemName, #itemDescription, #categoryID);
INSERT INTO Auction(ItemID, AuctionType, ReservationPrice, MaxPrice, AuctionEnd, AuctionStart, AuctionTTL)
VALUES(##IDENTITY,#auctionType,#reservationPrice,#maxPrice,#auctionEnd,#auctionStart,#auctionTTL);
COMMIT TRAN T1
RETURN ##IDENTITY
END
C# Code
cmd.CommandText = cmdText;
SqlParameter retval = new SqlParameter("#RETURN_VALUE", System.Data.SqlDbType.Int);
retval.Direction = System.Data.ParameterDirection.ReturnValue;
cmd.Parameters.Add(retval);
cmd.Parameters.AddRange(parameters);
cmd.Connection = connection;
connection.Open();
cmd.ExecuteNonQuery();
return (int)cmd.Parameters["#RETURN_VALUE"].Value;
Just tried on my box and this works for me:
In SQL Server:
DROP PROCEDURE TestProc;
GO
CREATE PROCEDURE TestProc
AS
RETURN 123;
GO
In C#
string cnStr = "Server=.;Database=Sandbox;Integrated Security=sspi;";
using (SqlConnection cn = new SqlConnection(cnStr)) {
cn.Open();
using (SqlCommand cmd = new SqlCommand("TestProc", cn)) {
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter returnValue = new SqlParameter();
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
cmd.ExecuteNonQuery();
Assert.AreEqual(123, (int)returnValue.Value);
}
}
I solved the problem:
you have to set SqlCommand.CommandType to CommandType.StoredProcedure in order to get return values and/or output parameters. I haven't found any documentation about that, but now everything works.
Do you get the value of you EXEC in TSQL? I wonder if refactoring the TSQL would help (and using SCOPE_IDENTITY():
so change:
COMMIT TRAN T1
RETURN ##IDENTITY
to:
SET #auctionID = SCOPE_IDENTITY()
COMMIT TRAN T1
RETURN #auctionID
(I would also change the other ##IDENTITY to SCOPE_IDENTITY())
As a minor optimisation, you could also use:
return (int)retval.Value;
but this side of things should have worked "as is" from what I can see (hence why I'm focusing on the TSQL).
Some one can also use this simple and short method to calculate return value from SP
In SQL:
Create Table TestTable
(
Int Id
)
CREATE PROCEDURE Proc_TestProc
#Id
AS
Begin
Set NOCOUNT ON //Use this line if you don't want to return any message from SQL
Delete from TestTable where Id = #Id
return 1
Set NOCOUNT OFF //NOCOUNT OFF is Optional for NOCOUNT ON property
End
Sql Server always returns Int type value only.
and in C#
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["TestConnectionString"].ToString()))
using (SqlCommand cmd = new SqlCommand("Proc_TestProc", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Id", 1);
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
conn.Open();
cmd.ExecuteNonQuery();
var result = returnParameter.Value;
}
You can also check your return value in SQL by using this command:
DECLARE #return_status int;
EXEC #return_status = dbo.[Proc_TestProc] 1;
SELECT 'Return Status' = #return_status;
print 'Returned value from Procedure: ' + Convert(varchar, #return_status); // Either previous or this line both will show you the value of returned value
you can use standart ways that you use before in normal queries but in Sql command you must write EXEC before your store procedure name and dont use commandtype like this :
SqlConnection con = new SqlConnection(["ConnectionString"])
SqlCommand com = new SqlCommand("EXEC _Proc #id",con);
com.Parameters.AddWithValue("#id",["IDVALUE"]);
con.Open();
SqlDataReader rdr = com.ExecuteReader();
ArrayList liste = new ArrayList();
While(rdr.Read())
{
liste.Add(rdr[0]); //if it returns multiple you can add them another arrays=> liste1.Add(rdr[1]) ..
}
con.Close();
I have the following query:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) output
AS
SET #Password =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
RETURN #b
GO
This compiles perfectly fine. I want to execute this query and get the return value. My code is below:
SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString());
System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
Note: Exception handling cut to keep the code short. Everytime I get to the last line, null is returned. What's the logic error with this code?
Mehrdad makes some good points, but the main thing I noticed is that you never run the query...
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
retval.Direction = ParameterDirection.Output;
ParameterDirection.ReturnValue should be used for the "return value" of the procedure, not output parameters. It gets the value returned by the SQL RETURN statement (with the parameter named #RETURN_VALUE).
Instead of RETURN #b you should SET #b = something
By the way, return value parameter is always int, not string.
I was having tons of trouble with the return value, so I ended up just selecting stuff at the end.
The solution was just to select the result at the end and return the query result in your functinon.
In my case I was doing an exists check:
IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE #RoleName = RoleName))
SELECT 1
ELSE
SELECT 0
Then
using (SqlConnection cnn = new SqlConnection(ConnectionString))
{
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "RoleExists";
return (int) cmd.ExecuteScalar()
}
You should be able to do the same thing with a string value instead of an int.
This is building on Joel's and Mehrdad's answers: you're never binding the parameter of the retval to the sqlcommand. You need a
sqlcomm.Parameters.Add(retval);
and to make sure you're running the command
sqlcomm.ExecuteNonQuery();
I'm also not sure why you have 2 return value strings (returnValue and retunvalue).
You say your SQL compiles fine, but I get: Must declare the scalar variable "#Password".
Also you are trying to return a varchar (#b) from your stored procedure, but SQL Server stored procedures can only return integers.
When you run the procedure you are going to get the error:
'Conversion failed when converting the varchar value 'x' to data type int.'
There are multiple problems here:
It is not possible. You are trying to return a varchar. Stored
procedure return values can only be integer expressions. See
official RETURN documentation:
https://msdn.microsoft.com/en-us/library/ms174998.aspx.
Your sqlcomm was never executed. You have to call
sqlcomm.ExecuteNonQuery(); in order to execute your command.
Here is a solution using OUTPUT parameters. This was tested with:
Windows Server 2012
.NET v4.0.30319
C# 4.0
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) OUTPUT
AS
BEGIN
DECLARE #b AS varchar(50) = (SELECT Password FROM dbo.tblUser WHERE Login = #a)
SELECT #b;
END
SqlConnection SqlConn = ...
var sqlcomm = new SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter output = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
ouput.Direction = ParameterDirection.Output;
sqlcomm.ExecuteNonQuery(); // This line was missing
returnValue = output.Value.ToString();
// ... the rest of code
} catch (SqlException ex) {
throw ex;
}
When we return a value from Stored procedure without select statement.
We need to use "ParameterDirection.ReturnValue" and "ExecuteScalar" command to get the value.
CREATE PROCEDURE IsEmailExists
#Email NVARCHAR(20)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
IF EXISTS(SELECT Email FROM Users where Email = #Email)
BEGIN
RETURN 0
END
ELSE
BEGIN
RETURN 1
END
END
in C#
GetOutputParaByCommand("IsEmailExists")
public int GetOutputParaByCommand(string Command)
{
object identity = 0;
try
{
mobj_SqlCommand.CommandText = Command;
SqlParameter SQP = new SqlParameter("returnVal", SqlDbType.Int);
SQP.Direction = ParameterDirection.ReturnValue;
mobj_SqlCommand.Parameters.Add(SQP);
mobj_SqlCommand.Connection = mobj_SqlConnection;
mobj_SqlCommand.ExecuteScalar();
identity = Convert.ToInt32(SQP.Value);
CloseConnection();
}
catch (Exception ex)
{
CloseConnection();
}
return Convert.ToInt32(identity);
}
We get the returned value of SP "IsEmailExists" using above c# function.
This SP looks very strange. It does not modify what is passed to #b. And nowhere in the SP you assign anything to #b. And #Password is not defined, so this SP will not work at all.
I would guess you actually want to return #Password, or to have SET #b = (SELECT...)
Much simpler will be if you modify your SP to (note, no OUTPUT parameter):
set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go
ALTER PROCEDURE [dbo].[Validate] #a varchar(50)
AS
SELECT TOP 1 Password FROM dbo.tblUser WHERE Login = #a
Then, your code can use cmd.ExecuteScalar, and receive the result.
There are two things to fix about this. First set up the stored procedure to store the value in the output ( not return ) parameter.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) output
AS
SET #b =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
RETURN
GO
This will but the password into #b and you will get it as a return parameter. Then to get it in your C# do this:
SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString());
System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar, 50);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter retval = new SqlParameter("#b", SqlDbType.VarChar, 50);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.Parameters.Add(retval);
sqlcomm.ExecuteNonQuery();
SqlConn.Close();
string retunvalue = retval.Value.ToString();
}
May be this will help.
Database script:
USE [edata]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertNewUser](
#neuname NVARCHAR(255),
#neupassword NVARCHAR(255),
#neuposition NVARCHAR(255)
)
AS
BEGIN
BEGIN TRY
DECLARE #check INT;
SET #check = (SELECT count(eid) FROM eusers WHERE euname = #neuname);
IF(#check = 0)
INSERT INTO eusers(euname,eupassword,eposition)
VALUES(#neuname,#neupassword,#neuposition);
DECLARE #lastid INT;
SET #lastid = ##IDENTITY;
RETURN #lastid;
END TRY
BEGIN CATCH
SELECT ERROR_LINE() as errline,
ERROR_MESSAGE() as errmessage,
ERROR_SEVERITY() as errsevirity
END CATCH
END
Application configuration file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="conStr" value="Data Source=User\SQLEXPRESS;Initial Catalog=edata;Integrated Security=True"/>
</appSettings>
</configuration>
Data Access Layer (DAL):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace DAL
{
public static class DAL
{
public static SqlConnection conn;
static DAL()
{
conn = new SqlConnection(ConfigurationManager.AppSettings["conStr"].ToString());
conn.Open();
}
}
}
Business Logic Layer(BLL):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using DAL;
namespace BLL
{
public static class BLL
{
public static int InsertUser(string lastid, params SqlParameter[] coll)
{
int lastInserted = 0;
try
{
SqlCommand comm = new SqlCommand();
comm.Connection = DAL.DAL.conn;
foreach (var param in coll)
{
comm.Parameters.Add(param);
}
SqlParameter lastID = new SqlParameter();
lastID.ParameterName = lastid;
lastID.SqlDbType = SqlDbType.Int;
lastID.Direction = ParameterDirection.ReturnValue;
comm.Parameters.Add(lastID);
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "InsertNewUser";
comm.ExecuteNonQuery();
lastInserted = (int)comm.Parameters[lastid].Value;
}
catch (SqlException ex)
{
}
finally {
if (DAL.DAL.conn.State != ConnectionState.Closed) {
DAL.DAL.conn.Close();
}
}
return lastInserted;
}
}
}
Implementation :
BLL.BLL.InsertUser("#lastid",new SqlParameter("neuname","Ded"),
new SqlParameter("neupassword","Moro$ilka"),
new SqlParameter("neuposition","Moroz")
);
You have mixed up the concept of the Return Value and Output variable.
1- Output Variable:
Database----->:
create proc MySP
#a varchar(50),
#b varchar(50) output
AS
SET #Password =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
C# ----->:
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;//This is optional because Input is the default
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter outputval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
outputval .Direction = ParameterDirection.Output//NOT ReturnValue;
string outputvalue = sqlcomm.Parameters["#b"].Value.ToString();
Suppose you need to pass Username and Password to Stored Procedure and know whether login is successful or not and check if any error has occurred in Stored Procedure.
public bool IsLoginSuccess(string userName, string password)
{
try
{
SqlConnection SQLCon = new SqlConnection(WebConfigurationManager.ConnectionStrings["SqlConnector"].ConnectionString);
SqlCommand sqlcomm = new SqlCommand();
SQLCon.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
sqlcomm.CommandText = "spLoginCheck"; // Stored Procedure name
sqlcomm.Parameters.AddWithValue("#Username", userName); // Input parameters
sqlcomm.Parameters.AddWithValue("#Password", password); // Input parameters
// Your output parameter in Stored Procedure
var returnParam1 = new SqlParameter
{
ParameterName = "#LoginStatus",
Direction = ParameterDirection.Output,
Size = 1
};
sqlcomm.Parameters.Add(returnParam1);
// Your output parameter in Stored Procedure
var returnParam2 = new SqlParameter
{
ParameterName = "#Error",
Direction = ParameterDirection.Output,
Size = 1000
};
sqlcomm.Parameters.Add(returnParam2);
sqlcomm.ExecuteNonQuery();
string error = (string)sqlcomm.Parameters["#Error"].Value;
string retunvalue = (string)sqlcomm.Parameters["#LoginStatus"].Value;
}
catch (Exception ex)
{
}
return false;
}
Your connection string in Web.Config
<connectionStrings>
<add name="SqlConnector"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Databasename;User id=yourusername;Password=yourpassword"
providerName="System.Data.SqlClient" />
</connectionStrings>
And here is the Stored Procedure for reference
CREATE PROCEDURE spLoginCheck
#Username Varchar(100),
#Password Varchar(100) ,
#LoginStatus char(1) = null output,
#Error Varchar(1000) output
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN
SET #Error = 'None'
SET #LoginStatus = ''
IF EXISTS(SELECT TOP 1 * FROM EMP_MASTER WHERE EMPNAME=#Username AND EMPPASSWORD=#Password)
BEGIN
SET #LoginStatus='Y'
END
ELSE
BEGIN
SET #LoginStatus='N'
END
END
END TRY
BEGIN CATCH
BEGIN
SET #Error = ERROR_MESSAGE()
END
END CATCH
END
GO
When you use
cmd.Parameters.Add("#RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
you must then ensure your stored procedure has
return #RETURN_VALUE;
at the end of the stored procedure.
The value you are trying to get is not a return value but an output parameter. You need to change parametere direction to Output.
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.Output;
command.ExecuteNonquery();
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
For .net core 3.0 and dapper:
If your stored procedure returns this:
select ID, FILE_NAME from dbo.FileStorage where ID = (select max(ID) from dbo.FileStorage);
Then in c#:
var data = (_dbConnection.Query<FileUploadQueryResponse>
("dbo.insertFile", whateverParameters, commandType: CommandType.StoredProcedure)).ToList();
var storedFileName = data[0].FILE_NAME;
var id = data[0].ID;
As you can see, you can define a simple class to help with retrieving the actual values from dapper's default return structure (which I found impossible to work with):
public class FileUploadQueryResponse
{
public string ID { get; set; }
public string FILE_NAME { get; set; }
}
This Line of code returns Store StoredProcedure returned value from SQL Server
cmd.Parameters.Add("#id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
Atfer Execution of query value will returned from SP
id = (int)cmd.Parameters["#id"].Value;