SQL insert issue. Running a stored procedure to insert rows to a table and returning the ID created. WHen I run it like this and have an output parameter #ID and use ExecuteNonQuery() it returns -1 for my int idinserted but does give me back the ID inserted. SHouldn't it return 1 since the record was inserted. I'd like to use ExecuteNonQuery to check the record was inserted then grab the inserted ID.
SQL INSERT
#person bigint,
#date datetime,
#ID bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO table(person,DATE_ADDED)
VALUES (#person,#date)
SELECT #ID = SCOPE_IDENTITY()
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#person", person);
cmd.Parameters.AddWithValue("#date", DateTime.Now);
SqlParameter output = new SqlParameter("#ID", SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.Parameters.Add(output);
int idinserted = (int)cmd.ExecuteNonQuery();
if (idinserted > 0)
{
int ID = output.Value;
}
When I do the insert and c# like this with ExecuteScalar()
SQL INSERT
#person bigint,
#date datetime
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO table(person ,DATE_ADDED)
VALUES(#person,#date )
SELECT SCOPE_IDENTITY()
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#person", person);
cmd.Parameters.AddWithValue("#date", DateTime.Now);
long ID = (long)cmd.ExecuteNonScalar();
ExecuteScalar() throws the following error
"Specificed Cast it not valid
Remove
SET NOCOUNT ON;
Because that removes the rowcount!
Related
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 am checking for a dupliacte emaild using stored proc
ALTER procedure [dbo].[Insertreg]
( #id int output,#FirstName varchar (50),#LastName varchar(50) ,#Dob datetime,
#Gender varchar(20) ,#MobileNo nchar(10) ,#Country varchar(50) ,
#State varchar (50),#EmailId varchar (50),#Password nchar (15),#result int output
)
as
begin
if exists(select EmailId from Profile_Master where EmailId=#EmailId)
set #result=0
else
begin
set #result=1
insert into Profile_Master(FirstName,LastName,Dob,Gender,MobileNo,Country,State,EmailId,Password)
values
(#FirstName,#LastName,#Dob,#Gender,#MobileNo,#Country,#State,#EmailId,#Password)
set #id=SCOPE_IDENTITY()
return
end
end
code behind
result = cmd1.Parameters.Add("#result", System.Data.SqlDbType.Int);
result.Direction = System.Data.ParameterDirection.Output;
var id = cmd1.ExecuteNonQuery();
but when i debug if emailid exists i am getting id value as -1 how can i resolve this?
Using ExecuteNonQuery with StoredProc returns -1. That's the expected behaviour.
Change your code to
if exists(select EmailId from Profile_Master where EmailId=#EmailId)
select 0 as result
else
select 1 as result
C#, you don't need to pass parameter here anymore
var id = cmd1.ExecuteScalar();
Since you are using OUTPUT parameter, you can also use #Pilgerstorfer Franz's approach
This is the expected behaviour for ExecuteNonQuery.
Your query is not affecting any rows.
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
You get the result as follows:
result = cmd1.Parameters.Add("#result", System.Data.SqlDbType.Int);
result.Direction = System.Data.ParameterDirection.Output;
cmd1.ExecuteNonQuery();
var id = result.Value;
Please try:
cmd1.ExecuteScalar();
var id=Convert.ToInt32(result.Value);
id is not an Id but just the number of affected rows since you're using ExecuteNonQuery instead of ExecuteScalar You should check result after ExecuteNonQuery to get the output variable.
result = cmd1.Parameters.Add("#result", System.Data.SqlDbType.Int);
result.Direction = System.Data.ParameterDirection.Output;
int numberOfAffectedRecords = (int)cmd1.ExecuteNonQuery();
// now result should have the output variable
If you want to have the newly created ID, you should use ExecuteScalar:
result = cmd1.Parameters.Add("#result", System.Data.SqlDbType.Int);
result.Direction = System.Data.ParameterDirection.Output;
int newID = (int)cmd1.ExecuteScalar();
// now result should have the output variable
Calling ExecuteNonQuery() will return the number of rows affected. As you did add an outputParameter you should access this one.
// access an output parameter
cmd1.ExecuteNonQuery();
var id = cmd1.Parameters["#result"].Value;
// OR: get the returnValue of a SP
var id = cmd1.ExecuteScalar();
EDIT
What about using this version of your sp
ALTER procedure [dbo].[Insertreg]
( #FirstName varchar (50),#LastName varchar(50) ,#Dob datetime,
#Gender varchar(20) ,#MobileNo nchar(10) ,#Country varchar(50),
#State varchar (50),#EmailId varchar (50),#Password nchar (15))
as
begin
if exists(select EmailId from Profile_Master where EmailId=#EmailId)
select -1;
else
begin
insert into Profile_Master(FirstName,LastName,Dob,Gender,MobileNo,Country,State,EmailId,Password)
values (#FirstName,#LastName,#Dob,#Gender,#MobileNo,#Country,#State,#EmailId,#Password)
select SCOPE_IDENTITY();
end
end
And afterwars only use
// no need for any output Parameters here...
int id = int.Parse(cmd1.ExecuteScalar().ToString())
to access your id value. Value will be greater than -1 if given mail is unique and -1 in case email already exists!
I am using ASP.NET 4.0, C# and SQL Server 2008 R2. I am getting UserName from the user in a webpage for stored in the SQL table User_Info2. Using SQL Server 2008 feature "computed column" I am generating the Vendor_ID automatically for every Insert using the stored procedure. In button click, after I insert the record I want to display the message with Vendor_ID, so please anyone tell me how to get the Vendor_ID column from the stored procedure ?
CREATE TABLE User_Info2
( SNo int Identity (2000,1) ,
Vendor_ID AS 'VEN' + CAST(SNo as varchar(16)) PERSISTED PRIMARY KEY,
UserName VARCHAR(30) NOT NULL
)
Stored procedure
ALTER PROCEDURE [dbo].[usp_User_Info2] #UserName VARCHAR(30)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info2 (UserName) VALUES (#UserName)
END
C# Code :
protected void BtnUserNext_Click(object sender, EventArgs e)
{
SqlConnection SqlCon = new SqlConnection(GetConnectionString());
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "usp_User_Info2";
cmd.Parameters.Add("#UserName", SqlDbType.VarChar).Value = txtUserName.Text.Trim();
cmd.Connection = SqlCon;
try
{
SqlCon.Open();
cmd.ExecuteScalar();
}
finally
{
string url = "../CompanyBasicInfo.aspx?Parameter=" + Server.UrlEncode ("+ Vendor_ID +");
ClientScript.RegisterStartupScript(this.GetType(),"callfunction",
"alert('Login created successfully for "+ Vendor_ID +"');
window.location.href = '" + url + "';", true);
SqlCon.Close();
}
}
You can output the inserted value using the OUTPUT clause, and then read it when you execute the stored procedure:
ALTER PROCEDURE [dbo].[usp_User_Info2] #UserName VARCHAR(30)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info2 (UserName)
OUTPUT Inserted.Vendor_ID
VALUES (#UserName)
END
and in your C# calling code:
object spResult;
string vendorID;
try
{
SqlCon.Open();
spResult = cmd.ExecuteScalar();
if(spResult != null) // check to make sure you got something back!
{
vendorID = spResult.ToString();
}
}
You can try this
ALTER PROCEDURE [dbo].[usp_User_Info2] #UserName VARCHAR(30)
AS
BEGIN
SET NOCOUNT ON;
declare #Id int
INSERT INTO User_Info2 (UserName) VALUES (#UserName)
SET #Id = Scope_Identity()
SELECT Vendor_ID From User_Info2 WHERE SNo = #Id
END
C#
try
{
SqlCon.Open();
string VendorID = cmd.ExecuteScalar() as string;
}
Also u can do like this
select top(1) Vendor_ID from User_Info2 order by SNo desc
You can get currently insert row with the help of SCOPE_IDENTITY()
SET #SNo = SCOPE_IDENTITY()
And below insert query you can execute select query on the #SNo
So it would be:
ALTER PROCEDURE [dbo].[usp_User_Info2]
(
#UserName VARCHAR(30),
#SNo int,
#Vendor_ID VARCHAR(50) OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info2 (UserName) VALUES (#UserName)
SET #SNo = Scope_Identity()
select #Vendor_ID as Vendor_ID from User_Info2 where SNo = #SNo
END
EDIT:
SqlParameter[] param= new SqlParameter[1];
param[0] = new SqlParameter("#Vendor_ID", 0);
param[0].Direction = ParameterDirection.Output;
// Here there will be a Stored Procedure Call
int VendorID = Convert.ToInt32(param[0].Value);
So now you will #Vendor_ID which is an Output variable.
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'
I am executing a stored procedure in c# (through vs2008) using ado.net with an ExecuteScalar command. The stored proc returns the pkey of the new record entered, but ExecuteScalar is returning null. I look in the database and a record has indeed been added. I could use an output parameter to get the value, but then I won't know why this didn't work.
When I execute the sp in ssms, the pkey is returned.
What am I doing wrong?
Here is the C# code:
public int SaveNewPerson(EPerson ePerson)
{
int newPersonPkey;
SqlConnection cn = new SqlConnection(cnn.PersonData);
using (cn)
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "People.dbo.AddNewPerson";
cmd.Parameters.Add("#LastName", SqlDbType.VarChar, 150).Value = ePerson.LastName;
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 150).Value = ePerson.FirstName;
cn.Open();
object result = cmd.ExecuteScalar();
newPersonPkey = int.Parse(result.ToString());
cn.Close();
}
catch (Exception e)
{
// call error method
throw new Exception(e.Message + " save new Person error ");
}
}
return newPersonPkey;
}
And this is the sp:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
declare #persons_PKey int
set #persons_PKey = ##IDENTITY
return #persons_PKey
end
The ExecuteScalar method returns the first field of the first record of the result, but as your query doesn't produce a result, it will return null.
You can either select the value instead of returning it from the stored procedure, or add a parameter with the direction set to ParameterDirection.ReturnValue to catch what the stored procedure returns.
Try changing the Stored Procedure to use a Select Statement to return the identity instead of using a return like this:
SELECT CAST(scope_identity() AS int)
Thus changing your procedure to:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
SELECT CAST(scope_identity() AS int)
end
From the documentation of the ExecuteScalar() on MSDN it says that it will return the first column of the first row in the result set or null otherwise if the result set is empty.