Using SCOPE_IDENTITY result in another query - sql

I'm having difficulties with this code
EXECUTE Environment.dbo.psu_some_psu
#instanceId = 1
,#serverId = 2
,#ip = '111.111.111.111'
,#clientName = 'dev-contact'
,#applicationId = 9
,#accountId = 35
,#userID = 22
DECLARE #restoreId INT
SET #restoreId = SCOPE_IDENTITY()
UPDATE Environment.dbo.restore_requests
SET Status = 1
WHERE Id = #restoreId
The stored procedure insert a row with indentity and with a status by default.
After the execution of the stored procedure i use scope_identity to get the ID of the inserted row.
But i cant get the update to work, i think there is a problem with the WHERE condition.
Thanks

It's called SCOPE_IDENTITY() because it returns the last identity value inserted in the current scope - and since each procedure has it's own scope - you do not get the expected results.
Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, if two statements are in the same stored procedure, function, or batch, they are in the same scope.
Use an output parameter to return the scope_identity() from inside the procedure that actually executes the insert statement.
Also, please note that if you are inserting multiple records, the scope_identity() will return only the last value - in such cases you use the output clause on the insert statement to get a table containing all the newly inserted identity values.
DECLARE #MyTableVar table( NewScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());

Related

Microsoft SQL Server - default value provided by stored procedure

Is it possible to have a non-null column where the value is generated at insert by calling a stored procedure the parameters of which are values passed to insert into the row?
For example, I have table User:
| username | name | surname | id |
Insert looks like this:
INSERT INTO USER (username, name, surname)
VALUES ('myusername', 'myname', 'mysurname');
The id column is populated with an (integer) value retrieved by calling stored procedure mystoredproc with parameters myusername, myname, mysurname.
A further question is, would this stored procedure be called on each row, or can it be called in a grouped fashion. For example, I'd like my stored procedure to take the name and append a random integer to it so that that if I insert 100 users with the name 'David', they will get the same id and the stored procedure will be called only once. A bit of a bad example on the second point.
Good day,
Is it possible to have a non-null column where the value is generated at insert by calling a stored procedure
Option 1: please check if this work for you
Specify Default Value for the Column and use "NOT NULL"
create trigger on the table AFTER INSERT
Inside the trigger, you can use the virtual table "inserted" in order to get the inserted values.
Using these values (using the inserted table) you can update the column using the logic you need for all the rows at once
** there is no need to use external SP probably, but you can execute SP from trigger if needed
** All executed by a trigger is in the same transaction as the original query.
would this stored procedure be called on each row
NO! The trigger will be executed once for all rows you insert in the same statement. The inserted table includes all the rows which were inserted. In your update section (step 4) you can update all the rows which were inserted in once and no need to execute something for each row
** If you do use external SP which is executed from the trigger then you can pass it all the inserted table as one using Table-Valued Parameter
------------------- update ---------------
Here is a full example of using this logic:
drop table if exists T;
CREATE TABLE T (id int identity(2,2), c int NOT NULL default 1)
GO
CREATE TRIGGER tr ON T AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
UPDATE T SET T.c = T2.C + 1
FROM inserted T2
INNER JOIN T T1 ON T1.id = T2.id
END
INSERT T(c) values (1) -- I insert the value 1 but the trigger will change it to 1+1=2
select * from T
GO
-- test multiple rows:
INSERT T(c) values (10),(20),(30),(40)
select * from T
GO
DECLARE #rc INT = 0,
#UserID INT = ABS(CHECKSUM(NEWID())) % 1000000 + 1;
WHILE #rc = 0
BEGIN
IF NOT EXISTS (SELECT 1 FROM dbo.Users WHERE UserId= #UserId)
BEGIN
INSERT dbo.Users(UserId) WHERE Username = #UserName SELECT #UserId;
SET #rc = 1;
END
ELSE
BEGIN
SELECT #UserId = ABS(CHECKSUM(NEWID())) % 1000000 + 1,
#rc = 0;
END
END

Inserting a row in a table and storing its scope identity in a variable in a stored procedure

I am a newbie in stored procedure and knows only basics of SQL. With the help of some SO questions I was able to figure out that SCOPE_IDENTITY() function can be used to get recently added row's identity value. Now I am trying to insert a row in a table using a stored procedure and I want that the identity of this newly inserted row must be assigned to a stored procedure's variable. Following is the code:
DECLARE #retID int = -1
SET #retID = (INSERT INTO [InfoValues]([InfoID],[Value],[UserID],[DateAdded],[DateUpdated]) VALUES(#item2,#item,#UserID,GETDATE(), GETDATE()); SELECT SCOPE_IDENTITY())
But this code is showing a syntax error at INSERT clause. So what is the correct way to do it?
You're close. You need to set the variable after the insert occurs.
DECLARE #retID int = -1;
INSERT INTO [InfoValues]
([InfoID],[Value],[UserID],[DateAdded],[DateUpdated])
VALUES
(#item2,#item,#UserID,GETDATE(), GETDATE());
SET #retID = SCOPE_IDENTITY();

Get inserted colm_ID from table A to used it in table B using stored procedure

I just want to ask how to get latest inserted ID from table A as an example and use it to enter a record in another table B?
If I got your question well, You need to perform two INSERT statements within one Stored Procedure and use the ID generated from the first statement to use it in the second statement, use SCOPE_IDENTITY()
create proc yourproc
(
-- parameter definitions here
)
as
begin
insert into Employee
(FN,LN,Address)
values
(#FN,#LN,#Address)
declare #EmployeeID int
set #EmployeeID = SCOPE_IDENTITY()
insert into EmpContact
(Empid, ContactType, ContactNumber)
values
(#EmployeeID, #ContactType, #ContactNumber)
end
SCOPE_IDENTITY and ##IDENTITY return the last identity values that are
generated in any table in the current session. However, SCOPE_IDENTITY
returns values inserted only within the current scope; ##IDENTITY is
not limited to a specific scope.
SCOPE_IDENTITY (Transact-SQL) - MSDN

How to get current value of unique identifier,assigned it to global variable and map it in ssis execute SQL task

I am using SSIS execute SQL task to execut a stored procedure.In the stored procedure I am passing certain input values and inserting it to a table.This table has got a unique identifier as primary key.As a return output i need the current value of the unique identifier.So I am taking that to a variable #logid as shown below
INSERT INTO logging.execution_log
(ParentLogID,
Description,
PackageName,
PackageGuid,
MachineName,
ExecutionGuid,
LogicalDate,
Operator,
StartTime,
EndTime,
Status,
FailureTask)
SELECT #ParentLogID,
#Description,
#PackageName,
Cast(#PackageGuid AS UNIQUEIDENTIFIER),
#MachineName,
Cast(#ExecutionGuid AS UNIQUEIDENTIFIER),
#logicalDate,
#operator,
Getdate(),
NULL,
#status,
NULL
SET #LogID = Cast(Scope_identity() AS INT) ----#logid is output variable from ssis
but it is not giving the intended result .Here the assignment of the global variable has been done using set operator
to #logid and mapped to execute sql ssis task variable.
After some research i found that
in order to assign the global variables i have to set SET NOCOUNT option ON as the first statement in the SQL query .I have done this as well.But it is not returning anything........by the way *why do we need to set this SET NOCOUNT parameter???*any help welcome
In order for a parameter to return the value assigned in the procedure body, the parameter must be declared with the OUT/OUTPUT keyword in the procedure, like this:
CREATE PROCEDURE procname (
#logID int OUTPUT,
other parameters
)
AS
body statements
Also, the corresponding argument in the EXEC statement should be supplied with that same keyword (OUT or OUTPUT), like this:
EXEC procname #someGlobalVar OUTPUT, other arguments
You could always SELECT SCOPE_IDENTITY() AS LogID at the end of your Execute SQL Task and then set your expected result set to single row and configure the result with the single column of LogID and map that to your SSIS global variable.
Let me know if you need me to clarify any of that.
You can use Scope_Identity to get a uniqueidentifier, that is used for Identity column.
To get a uniqueidentifier, you will need to assign it to a variable before using it
Set #LogID = NewID()
INSERT INTO logging.execution_log VALUES(...., #logID, ...)
Except if you misunderstand what a uniqueidentifier means
Identity columns are auto-generated sequence of integer 1,2,3,4... and works with Scope_Identity.

sql stored procedure not working(no rows affected)

trying to get this stored procedure to work.
ALTER PROCEDURE [team1].[add_testimonial]
-- Add the parameters for the stored procedure here
#currentTestimonialDate char(10),#currentTestimonialContent varchar(512),#currentTestimonialOriginator varchar(20)
AS
BEGIN
DECLARE
#keyValue int
SET NOCOUNT ON;
--Get the Highest Key Value
SELECT #keyValue=max(TestimonialKey)
FROM Testimonial
--Update the Key by 1
SET #keyValue=#keyValue+1
--Store into table
INSERT INTO Testimonial VALUES (#keyValue, #currentTestimonialDate, #currentTestimonialContent, #currentTestimonialOriginator)
END
yet it just returns
Running [team1].[add_testimonial] ( #currentTestimonialDate = 11/11/10, #currentTestimonialContent = this is a test, #currentTestimonialOriginator = theman ).
No rows affected.
(0 row(s) returned)
#RETURN_VALUE = 0
Finished running [team1].[add_testimonial].
and nothing is added to the database, what might be the problem?
There may have problems in two place:
a. There is no data in the table so, max(TestimonialKey) returns null, below is the appropriate way to handle it.
--Get the Highest Key Value
SELECT #keyValue= ISNULL(MAX(TestimonialKey), 0)
FROM Testimonial
--Update the Key by 1
SET #keyValue=#keyValue+1
b. Check your data type of the column currentTestimonialDate whether it is char or DateTime type, if this field is datetime type in the table then convert #currentTestimonialDate to DateTime before inserting to the table.
Also, check number of columns that are not null allowed and you're passing data to them.
If you're not passing data for all columns then try by specifying columns name as below:
--Store into table
INSERT INTO Testimonial(keyValue, currentTestimonialDate,
currentTestimonialContent, currentTestimonialOriginator)
VALUES (#keyValue, #currentTestimonialDate,
#currentTestimonialContent, #currentTestimonialOriginator)
EDIT:
After getting the comment from marc_s:
Make keyValue as INT IDENTITY, If multiple user call it concurrently that wont be problem, DBMS will handle it, so the ultimate query in procedure might be as below:
ALTER PROCEDURE [team1].[add_testimonial]
-- Add the parameters for the stored procedure here
#currentTestimonialDate char(10),
#currentTestimonialContent varchar(512),#currentTestimonialOriginator varchar(20)
AS
BEGIN
SET NOCOUNT ON;
--Store into table
INSERT INTO Testimonial VALUES (#currentTestimonialDate,
#currentTestimonialContent, #currentTestimonialOriginator)
END
Two issues that I can spot:
SELECT #keyValue=max(TestimonialKey)
should be
SELECT #keyValue=ISNULL(max(TestimonialKey), 0)
To account for the case when there are no records in the database
Second, I believe that with NOCOUNT ON, you will not return the count of inserted rows to the caller. So, before your INSERT statement, add
SET NOCOUNT OFF