I am trying to start usign stored procedures. Well, I currently have a query that is just returning a single value that is a string. I can't seem to see what I am doing incorrectly here.
The sql is below:
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #ReturnVal Varchar(20)
-- Insert statements for procedure here
set #ReturnVal = (select a.AccBCPublicId from [MyTable Goes Here] a where a.AccId = #ACCId)
return #ReturnVal
END
using (SqlCommand sqlCommand = new SqlCommand("[dbo].[My Stored Procedure]", sqlConnection) { CommandType = CommandType.StoredProcedure })
{
//clean the starting 0's before sending. Originally had leading zeros
sqlCommand.Parameters.Add(new SqlParameter("#ACCId", strAccId.TrimStart(Convert.ToChar("0"))));
SqlParameter returnParam = new SqlParameter("#ReturnVal", SqlDbType.NVarChar, 20) {Direction = ParameterDirection.ReturnValue };
sqlCommand.Parameters.Add(returnParam);
sqlCommand.ExecuteNonQuery();
string bcAccount = (string)returnParam.Value;
}
I keep getting the following error. I do see why it is seeing as int value type.
Conversion failed when converting the varchar value 'bc:99988' to data type int.
A value passed with the RETURN T-SQL statement can only be an integer expression, you can't pass back a string. It seems that the simplest option is to use ExecuteScalar
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select a.AccBCPublicId from [MyTable Goes Here] a where a.AccId = #ACCId
And in your code use
using (SqlCommand sqlCommand = new SqlCommand(.....))
{
sqlCommand.Parameters.Add(.....)
object result = sqlCommand.ExecuteScalar();
if(result != null)
string bcAccount = result.ToString();
....
}
Related
I have a stored procedure called lastID like this:
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id
FROM workorder
WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2))
ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
RETURN #id;
END
ELSE
BEGIN
SET #id = #f;
RETURN #id;
END
END
This stored procedure returns the last id from the table workorder, now I'm trying to execute this procedure in C#, this is the code:
private void lastWorkId()
{
String strConnString = "Server=.\\SQLEXPRESS;Database=recalls;Integrated Security=true";
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "lastID";
cmd.Parameters.Add("#id", SqlDbType.VarChar, 64).Direction = ParameterDirection.Output;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
String id = cmd.Parameters["#id"].Value.ToString();
lastid.Text = id.ToString(); //Putting the return value into a label
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
}
I don't know what are wrong with my code, because an exception is displayed, and this says
Conversion failed when converting the varchar value ' OT- 003-16 ' to data type int
I was wrong about my first answer, here is the updated answer:
Your stored procedure is setup with an OUTPUT parameter of type VARCHAR(64).
Within your proc you have a couple of RETURN #id; statements, which is actually returning a VARCHAR(64). You only need to set your OUTPUT variable within the stored procedure. The RETURN statement expects an integer expression. Here's the updated fixed sproc using OUTPUT appropriately:
ALTER PROCEDURE [dbo].[lastID](#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id FROM workorder WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
END
ELSE
BEGIN
SET #id = #f;
END
END
Error is basically should get fixed by cast
((RIGHT(work_id,2)) as int)
But code can be further condensed and improved.
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1 #id = isnull(work_id , 'No work orders') FROM workorder WHERE cast ((RIGHT(work_id,2)) as int)= (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
RETURN #id;
END
Stored procedure, inserting to the table, which has an identity column as ID
CREATE PROCEDURE InsertValue
#Value varchar(7),
#NewId int = 0 OUTPUT
AS
BEGIN
IF(NOT EXISTS(SELECT 1 FROM [Table1] WHERE Detail = #Value))
BEGIN
INSERT into [Table1] (Detail)
VALUES (#Value)
SET #NewId = SCOPE_IDENTITY();
END
END
C# code:
int newId=0;
SqlTransaction SqlTrans = null;
SqlConnection con = new SqlConnection("connection string");
con.Open();
cmd = new SqlCommand("InsertValue", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Value", "123"));
SqlParameter parId= new SqlParameter("#NewId",DbType.Int32);
parId.Value= 0;
parId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parId);
SqlTrans = con.BeginTransaction();
cmd.Transaction = SqlTrans;
try
{
cmd.ExecuteNonQuery();
// parId.Value is DBNULL
SqlTrans.Commit();
newId = Convert.ToInt32(parId.Value);
// Exception : This SqlTransaction has completed; it is no longer usable
}
catch (Exception e)
{
throw;
}
So can anyone help me with this? I want the transaction to be there in C# code, but need the value from out parameter.
If I access the value before committing the transaction, it is DBNull and if access after committing, getting exception while casting(the value is still DBNull)
This SqlTransaction has completed; it is no longer usable.
Take a look at the answers to these existing questions for This SqlTransaction has completed; it is no longer usable. Perhaps your stored procedure already commits the transaction, or the SQL Server is killing the transaction for some reason?
"This SqlTransaction has completed; it is no longer usable."... configuration error?
SqlTransaction has completed
Thanks everyone for the support and help.
Actually the problem was with the output parameter's default value.
I forgot to specify the condition in the question(now i have added it), which was preventing the value of the output parameter to be set each time.
As i was passing the output parameter value as 0 each time, so it was supposed to be 0 when it is not getting set in the SP.
But, the output parameter was getting as DBNull in case it is not set in the procedure.
So i changed the procedure to set the value of the parameter each time, irrespective of the condition.
CREATE PROCEDURE InsertValue
#Value varchar(7),
#NewId int = 0 OUTPUT
AS
BEGIN
SET #NewId = 0; -- Added to set it to 0
IF(NOT EXISTS(SELECT 1 FROM [Table1] WHERE Detail = #Value))
BEGIN
INSERT into [Table1] (Detail)
VALUES (#Value)
SET #NewId = SCOPE_IDENTITY();
END
END
I want to read Scope_Identity via output variable '#RoleID' from where I am assigning value of scope identity.
C#:
private static long createNewRoleInsert(ADB.Model.RolesModel roleModelObj, MSSQL sql)
{
bool killConnection = Utils.getConnection(ref sql);
long returnValue = 0;
try
{
sql.SetSProc("[dbo].[p_Role_dfn_createNew]");
sql.AddParam("#Title", roleModelObj.Title);
sql.AddParam("#Description", roleModelObj.Description);
sql.AddParam("#CreatedDate", roleModelObj.CreatedDate);
var RoleID = sql.ExecuteNonQuery();
if(RoleID!=0 && RoleID>0)
{
returnValue = RoleID;
}
}
finally
{
if (killConnection)
sql.Dispose();
}
return returnValue;
}
Stored procedure:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[p_Role_dfn_createNew]
#Title nvarchar(250),
#Description nvarchar(MAX) = NULL,
#CreatedDate DateTime,
#RoleID bigInt OUTPUT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON
DECLARE #l_object AS SYSNAME = OBJECT_NAME(##PROCID),
#l_error_msg AS NVARCHAR(2000)
BEGIN TRY
BEGIN TRAN
INSERT INTO [adb_TestDb].[dbo].[Role] ([Title], [Description], [CreatedDate])
VALUES (#Title, #Description, #CreatedDate)
COMMIT TRAN
SET #RoleID = SCOPE_IDENTITY();
RETURN #RoleID
END TRY
BEGIN CATCH
-- rollback any open/uncomitted transactions
IF XACT_STATE() IN ( -1, 1) ROLLBACK TRANSACTION
-- return an error containing the object, error number and error description
SELECT #l_error_msg = 'Error number : ' + CAST(ERROR_NUMBER()AS VARCHAR) + '. ' + ERROR_MESSAGE()
RAISERROR (#l_error_msg,16,1)
END CATCH
The ExecuteNonQuery method doesn't return the return value from the procedure, it returns the number of rows affected.
To get the return value you would add a parameter with ParameterDirection.ReturnValue, however that won't safely get you the value in #RoleID as the return value from a procedure can't be a bigint, it's always an int.
As you already have #RoleID as an output parameter you should add parameter to the command to get the value. Example:
SqlParameter roleIdParam = new SqlParameter("#RoleID", SqlDbType.BigInt);
roleIdParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(roleIdParam);
// execute command
long roleId = (long)roleIdParam.Value;
You need to add an output parameter in C# to get the value of #RoleID from the stored procedure. Here's an example of that:
using System.Data.SqlClient;
using (SqlConnection conn = new SqlConnection("connectionString"))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.p_Role_dfn_createNew";
// add other parameters...
cmd.Parameters.Add(new SqlParameter("#RoleID", SqlDbType.BigInt))
.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
returnValue = (long)cmd.Parameters["#RoleID"].Value;
}
Change the
RETURN #RoleID
to
SELECT #RoleID
or add the output parameter as explained in other answers
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 ;)
I am trying to return scalar from a database like this:
DbConnection cn = GetConnection2();
cn.Open();
// stored procedure
DbCommand cmd = GetStoredProcCommand(cn, "GetReason");
DbParameter param;
param = CreateInParameter("Reason_Number", DbType.String);
param.Value = number;
cmd.Parameters.Add(param);
param = CreateOutParameter("Result", DbType.String);
param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(param);
cmd.ExecuteScalar();
string reason;
reason = cmd.Parameters["#Result"].Value.ToString();
if (cn.State == ConnectionState.Open)
cn.Close();
return reason;
Here is my stored procedure:
-- =============================================
-- Create date: Today
-- Description: Input Reason # and Return Full Reason Name
-- =============================================
ALTER PROCEDURE [dbo].[GetReason]
#Reason_Number nvarchar(50),
#Result nvarchar(50) output
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT #Result = Field1
FROM dbo.Reasons
WHERE Field1 LIKE #Reason_Number + '%';
END
I am getting an error on the ExecuteScalar line:
System.InvalidOperationException occurred
Message="String[1]: the Size property has an invalid size of 0."
What am I doing wrong?
If you want to use ExecuteScalar, your stored proc needs to return the single row, single column from a SELECT:
ALTER PROCEDURE [dbo].[GetReason]
#Reason_Number nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT Field1
FROM dbo.Reasons
WHERE Field1 LIKE #Reason_Number + '%';
END
and then your code needs to read that value:
var returnedValue = cmd.ExecuteScalar();
and use it from there. Of course, in that case, you also do not need an OUTPUT parameter in your C# code....
Word of warning: that SELECT in your stored proc could potentially return multiple rows. You might want to add a TOP 1 to your select - just to be safe:
SELECT TOP 1 Field1
FROM dbo.Reasons
WHERE Field1 LIKE #Reason_Number + '%';
Just add an other one statement to the end of your stored procedure and remove OUTPUT parameter
SELECT #Result as 'Result'