SQL Insert into … ( SELECT *, SCOPE_IDENTITY() FROM … ) - sql

I created a stored procedure that should do 2 inserts in one
First step I want to create a new entry per insert into.
Second step I will catch the created Id from this entry
Third step I want to copie multiple entries per select from one table and insert those to the same table with the Id
Create PROCEDURE dbo.Rolle_Copie
#Id as int,
#newId as int = 0,
#Name AS nvarchar(50)
AS
INSERT INTO Rollen (RolleName)
VALUES (#Name)
#newId = SCOPE_IDENTITY()
INSERT INTO Berechtigung_Rolle (RefRolleId,RefBerechtigungId)
SELECT
RefBerechtigungId, #newId
FROM
Berechtigung_Rolle
WHERE
RefRolleId = #Id
RETURN
but I get an error
Wrong syntax next to #newId
Could somebody please enlight me what's wrong?
Any advice is greatly appreciated

don't forget to use SET
SET #newId = SCOPE_IDENTITY()

Related

Unable to get computed value with After Insert trigger

I'm using the FileTables feature and have setup a trigger to populate a FileProperties table whenever a file is copied to the SQL Server file share.
I'm trying to grab the file size (cached_file_size), and I get a value of zero. I set up the trigger the same way a standard FileTable does using DATALENTGH(file_stream). The code below is using the inserted tables' file_stream:
ALTER TRIGGER [dbo].[FileTable_Insert_Trigger]
ON [dbo].[Files]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #s_id UNIQUEIDENTIFIER,
#fs VARBINARY(MAX),
#nm NVARCHAR(255),
#fp NVARCHAR(MAX),
#cfs BIGINT,
#ft NVARCHAR(255);
SELECT #s_id = ins.stream_id FROM inserted ins;
SELECT #fs = ins.file_stream FROM inserted ins;
SELECT #nm = ins.name FROM inserted ins;
SELECT #fp = ins.file_stream.GetFileNamespacePath() FROM inserted ins;
SELECT #ft = ins.file_type FROM inserted ins;
SELECT #cfs = DATALENGTH(#fs);
INSERT INTO [FileProperties] (stream_id, [name], filepath, file_type,
cached_file_size, DateAdded, UserID)
VALUES (#s_id, #nm, #fp, #ft,
#cfs, CURRENT_TIMESTAMP, 1);
END
I've also tried grabbing the computed value directly from the FileTable:
SELECT #cfs = Files_1.cached_file_size
FROM [dbo].Files AS Files_1
WHERE Files_1.stream_id = #s_id;
Still getting zero. What am I missing here? Thank you.
[EDIT] I tried playing around with getting the DATALENGTH of other values such as the name (#nm) and stream_id (#s_id) and I do get the values correctly.

Set variable with Scope Identity after executing different stored proc

I am trying to set a declared variable in a stored procedure after making use of another stored procedure to INSERT a 'Case' first.
The pseudo code looks like this:
DECLARE #CaseId variable
INSERT Case into Case table
SET #CaseId using SCOPE_IDENTITY
IF Case.CaseID = #CaseId
--rest of script
The below script works as expected for me:
INSERT INTO Case (CaseRef, [Source], DateCreated, CaseType)
VALUES (#caseRef, #source, #dateCreated, #caseType)
SET #caseID = SCOPE_IDENTITY();
I've tried with the below script but it doesn't seem to set the variable. Is this possible? Or must I set it the way I'm doing in the above script?
EXEC sp_InsertCase #caseRef, #source, #dateCreated, #caseType
SET #caseID = SCOPE_IDENTITY();
scope_identity() does what it says on the tin - it gives you the last identity value generated in the current scope. A stored procedure defines a scope. So when the stored procedure that causes the identity value to be generated exits, you're no longer in the scope where the value was generated, so scope_identity() can't tell you anything.
What you can do is capture the scope_identity() value into a variable inside the stored procedure, and return it as an output parameter:
create table t(i int identity(1,1), j int);
go
create proc insert_and_get_scope #scopeid int = null output as
begin
insert t(j) values (1);
set #scopeid = scope_identity();
end
go
declare #scopeid int;
exec insert_and_get_scope #scopeid output;
select #scopeid;
You can see from the example below:
DROP TABLE IF EXISTS [dbo].[StackOverflow];
CREATE TABLE [dbo].[StackOverflow]
(
[RowID] INT IDENTITY(1,1) NOT NULL
);
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_StackOverflow]
AS
BEGIN;
INSERT INTO [dbo].[StackOverflow]
DEFAULT VALUES;
END;
GO
EXEC [dbo].[sp_StackOverflow];
SELECT SCOPE_IDENTITY();
it is not working, because it is not in the current scope:
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.
but you can try this:
DROP TABLE IF EXISTS [dbo].[StackOverflow];
CREATE TABLE [dbo].[StackOverflow]
(
[RowID] INT IDENTITY(1,1) NOT NULL
);
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_StackOverflow]
(
#RowID BIGINT OUTPUT
)
AS
BEGIN;
INSERT INTO [dbo].[StackOverflow]
DEFAULT VALUES;
SET #RowID = SCOPE_IDENTITY()
END;
GO
DECLARE #RowID BIGINT;
EXEC [dbo].[sp_StackOverflow] #RowID = #RowID OUTPUT;
SELECT #RowID;

SQL Insert Into Value with condition included

I'm trying to write a stored procedure to modify a session in my Sessions table. I need to be able to insert values into a specified row i.e. with a condition included although I'm not sure how.
Here is my code (I'm aware that I cannot do INSERT INTO > VALUES > WHERE but I'm trying to give you an idea of what I want to do).
CREATE PROCEDURE [dbo].[TT_Modify_Session]
#SessionName NVARCHAR(50),
#TrainingName NVARCHAR(100),
#Trainee NVARCHAR(20),
#TrainingDate DATE,
#SessionID INT
AS
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRAN
INSERT INTO dbo.TT_Sessions (SessionName, Trainee, TrainingDate, TrainingName)
VALUES #SessionName, #Trainee, #TrainingDate, #TrainingName
WHERE #SessionID = [SessionID]
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
PRINT ERROR_MESSAGE()
END CATCH
RETURN #sessionID
Any help is greatly appreciated!
You describe code to "modify" values that already exist in the table. That's an UPDATE...
(INSERT adds a new row to a table, and leaves all pre-existing rows as they were...)
UPDATE
dbo.TT_Sessions
SET
SessionName = #SessionName,
Trainee = #Trainee,
TrainingDate = #TrainingDate,
TrainingName = #TrainingName
WHERE
SessionID = #SessionID

Trigger not calling for huge rows insert

I have one table which consists of one trigger which will be called if any insert or update operation performed on that table.
This trigger will insert a new row in other physical table.
First I am taking the entire data to be inserted into a temporary table and then I am inserting data into my physical table(which has trigger).
After performing insert operation all the records in the temporary table are getting inserted into physical table but the trigger is executing for only first record, for rest of the records it is not executing.
Can anyone please help me with this issue.
NOTE : With cursor it is working fine but for performance issue I don't want to use cursor.
ALTER TRIGGER [dbo].[MY_TRG]
ON [dbo].[T_EMP_DETAILS]
FOR INSERT , UPDATE
AS
BEGIN
IF UPDATE(S_EMPLOYEE_ID)OR UPDATE(S_GRADE_ID)OR UPDATE(D_EFFECTIVE_DATE) OR UPDATE(S_EMPLOYEE_STATUS)
BEGIN
DECLARE #EmpId varchar(6)
DECLARE #HeaderId Int
DECLARE #FYStartYear varchar(4)
DECLARE #EffDate Smalldatetime
DECLARE #UpdatedBy varchar(10)
DECLARE #ActionType varchar(1)
DECLARE #RowCount Int
DECLARE #EmpRowCount Int
DECLARE #AuditRowsCount Int
DECLARE #EMP_STATUS VARCHAR(1)
DECLARE #D_FIN_START_YEAR DATETIME
DECLARE #Food_Count int
SELECT #FYStartYear = CAST(YEAR(D_CURRENT_FY_ST_DATE)AS VARCHAR) FROM dbo.APPLICATION WHERE B_IS_CURRENT_FY = 1
SELECT #UpdatedBy = 'SHARDUL'
select #EmpId = S_EMPLOYEE_ID from inserted
select #HeaderId = N_HEADER_TXN_ID from inserted
select #EffDate = D_EFFECTIVE_DATE from inserted
select #FLEXI_AMT = N_FLEX_BASKET_AMT from inserted
select #EMP_STATUS = S_EMPLOYEE_STATUS from inserted
select #D_FIN_START_YEAR=D_FIN_START_DATE from inserted
SELECT #RowCount = count(*) from T_EMP_DETAILS
WHERE S_EMPLOYEE_ID = #EmpId and
SUBSTRING(CAST(D_EFFECTIVE_DATE AS VARCHAR),1,11) = SUBSTRING(CAST(#EffDate AS VARCHAR),1,11)
BEGIN
exec INSERT_DEFAULT_VALUES #EmpId,#HeaderId,#UpdatedBy
END
That's one of many reasons Bulk is so fast :). Read Bulk Insert syntax and you'll see FIRE_TRIGGERS parameter. Use it.
As I wrote in my comment - you are using inserted in improper way. As written now it will work only for 1 row.
The second one is a WEIRD number of variables, and only few are used, why?
Third - you are using SP in the end of batch, you need to post it's code, I bet there is some insert in it, maybe you could avoid using this SP and insert directly in some table from inserted.

SQL Select or Insert return ID

Alright so a quick SQL question here(using sql-server-2008).
I have a mapping table names with the following columns
ID DisplayName
What I want to do is first
SELECT [ID] FROM [names] WHERE [DisplayName] = 'chuck';
BUT, if the name 'chuck' doesn't exist in the database, I would like to create it, and return the auto incremented ID.
I was wondering if SQL had some built in way of doing this in an easy way, or if I have to go the long route?
long route being something like this
SELECT COUNT(ID) AS count, ID FROM names WHERE DisplayName='chuck'
IF(count > 0)
SELECT ID as ReturnID;
ELSE
BEGIN
INSERT INTO names(DisplayName) values('chuck');
SELECT scope_identity() as ReturnID;
END
I didn't test that last statement, but I assume the long way would be something like that. If there is no built in way, I'd appreciate it if someone could simply correct that statement(as I'm sure it isn't completely correct).
You should take care about transactions as well:
set XACT_ABORT on
begin tran
declare #ID int
select #ID = ID from names with (holdlock, updlock) WHERE DisplayName='chuck'
if ##rowcount = 0
begin
INSERT INTO names(DisplayName) values('chuck');
set #ID = scope_identity();
end
select #ID as ReturnID;
commit tran
Note the usage of table hints - holdlock and updlock. They prevent another thread from executing exactly the same query and creating the row a second time. For more information look for isolation, synchronization, deadlocks, concurrent updates.
I would do:
IF (NOT EXISTS(SELECT null from names where DisplayName='Chuck'))
INSERT INTO Names (DisplayName) Values ('Chuck')
SELECT ID as ReturnID FROM Names where DisplayName='Chuck'
Doesn't save much though
go
create table names
(
Id int primary key identity(1,1),
displayname varchar(100),
);
go
create procedure P1
#displayname varchar(100)
as
insert into names (displayname)
select #displayname
where not exists (
select * from names, (select #displayname as displayname) as names2
where names.displayname = names2.displayname);
-- race condition is possible here,
-- but in some cases you still may get away with this
select id from names where displayname = #displayname;
go
declare #dn varchar(100);
set #dn = 'chuck'; exec P1 #dn; exec P1 #dn; exec P1 #dn;
set #dn = 'buck'; exec P1 #dn; exec P1 #dn;
select * from names;
go
drop table names; drop procedure P1;
Output would 1, 1, 1, 2, 2 and the table content two rows big.