I am executing an Insert query. I want to return the identity element. I am also using this same stored procedure. Inside another stored procedure to return the identity element.
Alter Proc Proc1
#name varchar(10),
#value int
As
Begin
insert into Table1
values (#name, #value)
return SCOPE_IDENTITY()
C# code:
I have a method to call my database every time, so I use that
_database.StoredProcedure = "Proc1";
_database.parameter("name","michael");
_database.parameter("value",10);
int id = Convert.ToInt32(_database.ExecuteScalar());
Here, I get id=0 every time //BUG
SQL other stored procedure:
Alter Proc2
// Some other logic
Execute #id = Proc1 #name, #value // THIS WORKS
Now, If I change Proc1's last line to Select SCOPE_IDENTITY() from RETURN SCOPE_IDENTITY() then C# code works but Proc2 returns 0.
What should I do such that it works in C# code and in Proc2 also.
I thought about an output parameter, but I don't know how would I call it with my this database method in C#.
If you want data out of a procedure the correct thing is to use output parameters. Do NOT use the return_value from your procedures. This value indicates a status of the execution, not data from the procedure.
Here is an example of what this might look like.
Alter Proc Proc1
#name varchar(10),
#value int,
#IdentityValue int OUTPUT
As
Begin
insert into Table1 values (#name,#value)
Select #IdentityValue = SCOPE_IDENTITY()
END
select * from table1
GO
Alter Proc2
(
#name varchar(10)
, #value int
, #IdentityValue int OUTPUT
)
as
//SOme other logic
declare #IdentityValue int
Execute Proc1 #name, #value, #IdentityValue OUTPUT
GO
Also, please notice that you have an insert in Proc1 but you don't specify the columns. This is very bad practice. If your table structure changes your procedure is broken. You should ALWAYS specify the columns in your insert.
Change your procedure body to like below, to change the RETURN statement to SELECT SCOPE_IDENTITY()
Alter Proc Proc1
#name varchar(10),
#value int
As
Begin
insert into Table1 values (#name,#value);
SELECT SCOPE_IDENTITY();
END
In that case, make it a output parameter and set that output parameter to scope_identity
Alter Proc Proc1
#name varchar(10),
#value int,
#ID INT OUTPUT
As
Begin
insert into Table1 values (#name,#value);
SET #ID = SCOPE_IDENTITY();
END
You can call the procedure
cmd.Parameters.Add("#ID", SqlDbType.Int, 0, "ID");
cmd.Parameters["#ID"].Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
int id = (int)cmd.Parameters["#ID"].Value;
Related
Model model=new Model();
model.id=0;
model.name="";
model.surname="";
db.Model.Add(model);
db.SaveChanges();
int id_returned=model.id;
This block gives me the id field of the inserted row.
But i use stored procedure for this insert process.
Model model=new Model();
model.id=0;
model.name="";
model.surname="";
int returned_id2=db.Sp_Model_insert(model.name, model.surname);
this block inserts the row. returned_id2 returns -1.
How can i get the row id that inserted via Sp ?
Here is my Stored Procedure:
USE [KayaShop]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [KS_ACCOUNTS].[SP_AccountModules_Insert](
#Area nvarchar(50),
#Controller nvarchar(50),
#Action nvarchar(50),
#SubAction nvarchar(50),
#Name nvarchar(50),
#TopName nvarchar(50),
#Level int,
#Visible int,
#Clickable int,
#HomePage int,
#Icon nvarchar(20),
#Status int
)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [KS_ACCOUNTS].[AccountModules]
([Area]
,[Controller]
,[Action]
,[SubAction]
,[Name]
,[TopName]
,[Level]
,[Visible]
,[Clickable]
,[HomePage]
,[Icon]
,[Status])
VALUES
(#Area,
#Controller,
#Action,
#SubAction,
#Name,
#TopName,
#Level,
#Visible,
#Clickable,
#HomePage,
#Icon,
#Status)
END
SELECT SCOPE_IDENTITY()
Add this after the insert query in your stored procedure
Multiple ways:
SCOPE_IDENTITY() - https://msdn.microsoft.com/en-us/library/ms190315.aspx - Returns the last single IDENTITY value in the current session's current scope.
##IDENTITY - https://msdn.microsoft.com/en-us/library/ms187342.aspx - Returns the last single IDENTITY value in the current session (regardless of scope).
INSERT INTO ... VALUES ... OUTPUT - https://msdn.microsoft.com/en-us/library/ms177564.aspx - outputs all inserted values, including IDENTITY values, this is the only way to retrieve IDENTITY values when your INSERT statement will insert multiple rows.
As your stored procedure only seems to insert a single row, you should be fine with SCOPE_IDENTITY.
Note that if all your stored procedure does is INSERT you probably don't need a stored procedure, your database client code should perform the INSERT directly.
Note that you should not use the RETURN keyword to return the IDENTITY value to the caller, you should use output parameters - a stored procedure's return-value is intended to convey status information and it is restricted to just an int value (e.g. return 0 for success).
I added these lines to the end of my sp:
SELECT #Id =SCOPE_IDENTITY()
RETURN
and at my code side:
int Id = 0;
ObjectParameter prm = new ObjectParameter("Id", typeof(int));
DB.SP_AccountModules_Insert(DTO.Area, DTO.Controller, DTO.Action, DTO.SubAction, DTO.Name, DTO.TopName, DTO.Level, DTO.Visible, DTO.Clickable, DTO.HomePage, DTO.Icon, DTO.Status, prm);
Id = Convert.ToInt32(prm.Value);
return Id;
i send and out parameter from my code to my sp, then i assign the last inserted id to my parameter and return it to my code. thats it.
Thank you for all help.
I have a database which stores information about a library (books, authors & categories).
But I can't get my stored procedure to work for inserting data. The stored procedure itself executes fine, but when I perform a test, it simply doesn't add anything to the database. Can anyone see what I'm missing?
This is my stored procedure (for category):
USE MyLibrary
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'CategoryInsert' AND TYPE = 'P')
BEGIN
DROP PROC CategoryInsert
END
GO
CREATE PROCEDURE CategoryInsert
(
#Id int out,
#Name nvarchar(255),
#InsertedBy nvarchar(120),
#InsertedOn datetime
)
AS
DECLARE #CurrentId int
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
BEGIN
SET #Id = -100
RETURN
END
INSERT INTO Category
(
Name,
InsertedBy,
InsertedOn
)
VALUES
(
#Name,
#InsertedBy,
#InsertedOn
)
SET #Id = SCOPE_IDENTITY()
GO
This is my test:
USE MyLibrary
GO
DECLARE #NewId int
DECLARE #date datetime
SET #date = getdate()
EXEC CategoryInsert #NewId, 'Testing', 'AL', #date
SELECT #NewId
GO
This line:
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
The equality check will always return true because you're essentially comparing WHERE 1 = 1, which means that #CurrentID will always have a value and thus your stored procedure will always return before the INSERT happens.
I saw few solutions here but none worked. I tried SCOPE_IDENTITY() didn't wotk. the id is autoincrement.
This is my stored procedure
CREATE PROCEDURE [dbo].[uploadVid]
#video varbinary(MAx),
#vidTitle varchar(50),
#vidCategory varchar(50),
#vidDate date,
#vidDescription varchar(Max),
#vidName varchar(50),
#vidSize bigint
AS
INSERT INTO Video(video, vidTitle, vidCategory, vidDate, vidDescription, vidName, vidSize)
VALUES (#video, #vidTitle, #vidCategory, #vidDate, #vidDescription, #vidName, #vidSize)
& in the back end I tried
Object i = register.ExecuteScalar();
&
int newId = (Int32)register.ExecuteScalar();
I put a break point and it gave me a value of null or 0. any help appreciated
Thanks
try this
CREATE PROCEDURE [dbo].[uploadVid]
#video varbinary(MAx),
#vidTitle varchar(50),
#vidCategory varchar(50),
#vidDate date,
#vidDescription varchar(Max),
#vidName varchar(50),
#vidSize bigint
AS
begin
declare #id as int --assuming your identity column is int
INSERT INTO Video(video, vidTitle, vidCategory, vidDate, vidDescription, vidName, vidSize)
VALUES (#video, #vidTitle, #vidCategory, #vidDate, #vidDescription, #vidName, #vidSize)
set #id = scope_identity()
select #id --return the value for executescaler to catch it
end
Probably you don't execute the commands in the correct sequence: (supposing you are using an SQL Server DB)
SqlCommand cmd = new SqlCommand("uploadVid", connnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(.....)
......
// After adding the parameters you execute the command to insert the new row....
int rowsInserted = cmd.ExecuteNonQuery();
if(rowsInserted > 0)
{
SqlCommand cmd1 = new SqlCommand("SELECT SCOPE_IDENTITY()", connection);
int newID = (int)cmd1.ExecuteScalar();
}
ExecuteScalar returns only the value of the first row in the first column of the query executed. In case of an insert this value is meaningless. You need an ExecuteNonQuery that returns the rows inserted by the command. After that run a new command with the SELECT SCOPE_IDENTITY() command text with the ExecuteScalar. This, of course, if you cannot modify the SP, the answer from th1rdey3 is better if you could change the proc because it avoids a run-trip to the database.
I am creating a web page to store data which is read from a Microsoft Excel worksheet.
I am passing the data to a stored procedure in SQL Server 2008.
Here is my C# code:
SqlConnection conn = new SqlConnection(AppDB);
conn.Open();
SqlCommand command = new SqlCommand();
command.Connection = conn;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "sp_ins_TaskDetails_from_Excel";
command.Parameters.AddWithValue("#TaskDetails", dtTaskDetailsFromExcel);
string sReturnValue = command.ExecuteNonQuery().ToString();
The stored procedure has one user defined table data type as parameter.
Here is my stored procedure:
ALTER PROCEDURE dbo.sp_ins_TaskDetails_from_Excel
(
#TaskDetails TypeInsertTaskFromExcel11 readonly
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE
#ProjectID int,
#ProjectTeamID int,
#TeamLeaderUserID int,
#TaskCategoryName varchar(max),
#TaskDescription varchar(max),
#TeamMemberUserID int,
#TaskPriorityName varchar(10),
#PlanDuration float,
#PlanStartDate datetime,
#PlanEndDate datetime,
#TaskTypeName varchar(30),
#TaskStatusName varchar(30),
#TaskAllotName varchar(10),
#CreatedBy varchar(30),
#CreatedDate datetime,
#ISMailSend bit,
#Isvisible bit,
#UniqueID int
DECLARE TMSTaskDetailFromExcelCursor CURSOR FOR SELECT
ProjectID,
ProjectTeamID,
TeamLeaderUserID,
TaskCategoryName,
TaskDescription,
TeamMemberUserID,
TaskPriorityName,
PlanDuration,
PlanStartDate,
PlanEndDate,
TaskTypeName,
TaskStatusName,
TaskAllotName,
CreatedBy,
CreatedDate,
ISMailSend,
Isvisible,
UniqueID
FROM #TaskDetails
OPEN TMSTaskDetailFromExcelCursor
FETCH NEXT FROM TMSTaskDetailFromExcelCursor INTO
#ProjectID,
#ProjectTeamID,
#TeamLeaderUserID,
#TaskCategoryName,
#TaskDescription,
#TeamMemberUserID,
#TaskPriorityName,
#PlanDuration,
#PlanStartDate,
#PlanEndDate,
#TaskTypeName,
#TaskStatusName,
#TaskAllotName,
#CreatedBy,
#CreatedDate,
#ISMailSend,
#Isvisible,
#UniqueID;
WHILE ##FETCH_STATUS=0 BEGIN
-- Insert statements for procedure here
INSERT INTO ManageTasks (ProjectID, ProjectTeamID, TeamLeaderUserID,
TaskCategoryName,TaskDescription, TeamMemberUserID, TaskPriorityName,
PlanDuration, PlanStartDate, PlanEndDate, TaskTypeName,
TaskStatusName, TaskAllotName, CreatedBy, CreatedDate, ISMailSend, Isvisible,UniqueID)
VALUES (#ProjectID, #ProjectTeamID, #TeamLeaderUserID, #TaskCategoryName,
#TaskDescription, #TeamMemberUserID, #TaskPriorityName, #PlanDuration,
#PlanStartDate, #PlanEndDate, #TaskTypeName, #TaskStatusName,
#TaskAllotName, #CreatedBy, #CreatedDate, #ISMailSend,#Isvisible,#UniqueID);
FETCH NEXT FROM TMSTaskDetailFromExcelCursor INTO
#ProjectID,
#ProjectTeamID,
#TeamLeaderUserID,
#TaskCategoryName,
#TaskDescription,
#TeamMemberUserID,
#TaskPriorityName,
#PlanDuration,
#PlanStartDate,
#PlanEndDate,
#TaskTypeName,
#TaskStatusName,
#TaskAllotName,
#CreatedBy,
#CreatedDate,
#ISMailSend,
#Isvisible,
#UniqueID;
END;
CLOSE TMSTaskDetailFromExcelCursor;
DEALLOCATE TMSTaskDetailFromExcelCursor;
END
It receives the data and using a cursor in the same stored procedure each row will be inserted using an Insert statement in the same procedure.
While executing, all the data from Excel is passed to the stored procedure as exactly mentioned in the user defined table type.
But, the values are not stored in database and the stored procedure returns -1.
All the values are in correct format and order. I don't know what is going wrong.
Is there something I should change in the stored procedures?
UPDATE: my code is behaving as expected by there was a typo in the stored procedure that was the reason it was failing.
I can't seem to figure out why or how to fix this because I am not getting any errors what I am getting is the return value is 0 which means fail.
Here is my .net code:
SqlParameter returnValue= new SqlParameter("returnValue", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
cmd.ExecuteNonQuery();
result = Convert.ToInt32(returnValue.Value); //1 success and 0 failed
My stored procedure:
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT ON
DECLARE #Result int
SET #Result = 0
UPDATE Employee
SET name = #name
WHERE employee_id = #employee_id
IF (##rowcount = 1)
BEGIN
SET #Result = 1
END
SET NOCOUNT OFF
RETURN #Result
END
So if I just execute the stored procedure from SQL Server Management Studio, it does update my row successfully without any error
EXEC EmployeeUpdate 34,'John John'
Return Value = 1
Replace the following
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT ON
With Following
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT OFF
SET NOCOUNT ON is indicating that number of rows effect by T-SQL will
not be returned
SET NOCOUNT OFF mean that number of rows effect by
T-SQL will be returned.
I would suggest to remove returnValue parameter altogether and just use the return value of ExecuteNonQuery() method instead:
int rowsAffected = cmd.ExecuteNonQuery();
result = rowsAffected == 1 ? 1 : 0;
Stored procedure:
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
UPDATE Employee
SET name = #name
WHERE employee_id = #employee_id
END