How to get a table identity inserted by instead of insert trigger? - sql-server

I have a problem described as follows: I have a table with one instead of insert trigger:
create table TMessage (ID int identity(1,1), dscp varchar(50))
GO
Alter trigger tr_tmessage on tmessage
instead of insert
as
--Set NoCount On
insert into tmessage
select dscp from inserted
GO
Alter proc P1
As
--Set NoCount On
insert into tmessage
(dscp)
values('some data')
Select SCOPE_IDENTITY()
GO
When I execute P1 it returns Null for SCOPE_IDENTITY() instead of the identity of the table. I even tried Output clause in the insert statement in the proc. but again the output table Identity field that gets filled from inserted in the Output clause is 0 in this case.
Any help would be appreciated.

Well, you've got yourself quite a pickle there.
From the one hand, you need the instead of insert trigger on your table, but from the other hand, you want to get the identity that this trigger generates back to the stored procedure that activated it.
Since there is no way to send parameters to and from triggers, you will have to do one of 3 things:
Find some way to eliminate the need for that instead of trigger.
This is my best recommendation.
Break your stored procedure to 2 parts: One part will do everything until the insert into statement (including it), thus activating the instead of insert trigger, and the other part that will do all operations needed after the trigger. this way you can use the scope_identity() inside the instead of insert trigger and send it's return value to the second stored procedure as a parameter.
Note: this design means you have to insert records one by one. should you try to insert more then one record, scope_identity() will only return the identity of the last row inserted by the trigger.
Find some way of passing data between the stored procedure and the instead of trigger. Since triggers can't except or return parameters, you will have to use either a temporary table or a regular table. This suggested solution is only suggested as a last resort, since it will complicate your code and probably cause some performance issues as well. Also, you will have to find a way to hold execution of the stored procedure until the instead of trigger will finish it's work. I can give you some pointers on how to share data between the procedure and the trigger, but I really suggest not to choose this solution.

SCOPE_IDENTITY() return the value from current scope and that is stored procedure outside from stored procedure it will be null.use ##identity to get last inserted identity.

Related

Get trigger inserted row id's in stored procedure

I have a stored procedure which updates multiple rows in a column as mentioned below:
update tableA
set isactive = 0
where email = ''
TableA has update trigger to insert into tableALog if isactive is changed.
Now in my stored procedure after update statement is executed I need to get tableALog primary key values.
I have used following ways bu no luck.
##identity - failed because it returns last updated value. But I need list of primary key values inserted in log table
OUTPUT inserted. - cannot use this because it always works on current scope in stored procedure. But I need table values which are inserted from trigger.
Please let me know if you have any suggestions.
This started as a comment but it's getting too long, so...
Sharing data between stored procedures and the triggers they activate is tricky,
Since triggers can't take parameters not can they return values.
From my experience, The best way to achieve such a thing involve adding a column to the table the trigger is set on to identify the records the trigger is working on, and adding a table (could be a temporary table) for the trigger to output the data and the stored procedure to read from.

Using Same Stored Procedure for Inserting List of Values and Query Results

I have a stored procedure to insert a row, with a list of values which came as input parameters, into a table (tmp).
This table mirrors another table (data), and I'm looking for a way to use the same SP to insert a row from data into tmp.
I've seen Pass result of a query into stored procedure, but I can't put INSERT in a UDF.
Is there an easy way, not requiring
a query which puts all the values into variables and sends the variables?
a table-typing or other additions to our already-too-full database
Edit The desired result would be a way to write something like
EXEC sp_insert (SELECT c1,c2,c3 FROM data)
Maybe you can use variable table as the parameter for the SP (search for this)
It needs to define user defined table type , but I'm using this method.
Table used as a parameter can get values from inserting or selecting from other table.
alter procedure sp_insert
#table your_table_type readonly
AS
BEGIN
--here you take a row (maybe the only one) from #table and insert it to TMP
END

SQL Server add auto serial id to additional field during insert

I have an insert statement in a stored procedure who's primary key is a serial id. I want to be able to populate an additional field in the same table during the same insert statement with the serial id used for the primary key. Is this possible?
Unfortunately this is a solution already in place... I just have to implement it.
Regards
I can't imagine a reason why you would want a copy of the key in another column. But in order to do it, I think you'll need to follow your update with a statement to get the value of the identity key, and then an update to put that value in the other column. Since you're already in a stored procedure, it's probably ok to have a few extra statements, instead of doing it in the very same one.
DECLARE #ID INT;
INSERT INTO TABLE_THINGY (Name, Address) VALUES ('Joe Blow', '123 Main St');
SET #ID = SCOPE_IDENTITY();
UPDATE TABLE_THINGY SET IdCopy = #Id WHERE ID = #ID
If it's important that this be done every single time, you might want to create a Trigger to do it; beware, however, that many people hate triggers because of the obfuscation and difficulty in debugging, among other reasons.
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
I agree, it is odd that you would replicate the key within the same table but with that said you could use a trigger, thus making it have no impact to current insert statements.
The below trigger is "After Insert" so technically it happens milliseconds after the insert if you truly wanted it to happen at the same time you would use a FOR INSERT instead and just replicate the logic used to create the serial id field into the new field.
CREATE TRIGGER triggerName ON dbo.tableName
AFTER INSERT
AS
BEGIN
update dbo.tableName set newField = inserted.SerialId where serialId = inserted.SerialId
END
GO
You could have a computed column that just returns the id column.
CREATE TABLE dbo.Products
(
ProductID int IDENTITY (1,1) NOT NULL
, OtherProductID AS ProductID
);
Having said that, data should only live in one place and to duplicate it in the same table is just a wrong design.
No, you cannot use the same insert statement for identity Id and copy that auto generated Id to the same row.
Multi-Statement using OUTPUT inserted or Trigger is your best bet.

SQL Server trigger - get variable from the first Insert stored procedure?

I have an insert stored procedure with incremented Id (int). I'll like to take that Id and insert it to another table and also one of variable from the insert stored procedure.
I know you can do select from inserted but if I'm not mistaking that allowed you to select values from the inserted row.
Is there anyway to persevere the variable after executed the stored procedure and pass it to trigger?
Edit: sorry, let me included the stored procedure that I'm using. Table foo have a Id that is auto incremented and I want a trigger to insert the foo's Id and the #mid to another table after this stored procedure is run. However as you can see that #mid is not being insert to table foo.
ALTER PROCEDURE [dbo].[foo]
#userName varchar(50),
#somefoo varbinary(max),
#mid int
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO fooTable(UserName, SomeFoo)
VALUES (#userName, #somefoo);
END
The inserted pseudo-table allows you to select the value that is now in the table. The deleted pseudo-table allows you to select the value that used to be in the table before the insert happened. Since you say insert proc i am assuming it's not an insert/update proc. I am not clear on what you want to do. You want the trigger to copy the identity field and one other column? Easy. You want the trigger to copy the identity field and a proc parameter that is not actually stored in the table? Impossible - but if that's what you want, then you can do it in the proc instead.
1) Trigger:
Insert into foo (a, b)
select my_identity, some_column
from inserted
2) Proc:
..do main insert...
insert into foo (a, b)
select scope_identity(), #some_parameter
You can use your table extended property for your purpose.
step 1 : define a extended property for your table.
step 2 : in stored procedure before insert into your table set defined extended property by your parameter.
EXEC sys.sp_updateextendedproperty #name=N'#ParameterName', #value='YourValue'
step 3 : in trigger get defined extended property and use it.
use sys.extended_properties table for get defined extended property.

Inserting a identity column value into another table

Good Morning. I have two tables, and one references the other. When I insert into the primary table, the primary key is auto-generated, viz Identity field. I need to insert this value into the second table.
I found out using the OUTPUT clause will give me the just inserted identity value, ans so I tried this.
insert into owners (pId)
insert into personal (firstName)
output inserted.pId
values ('fn')
It doesn't work though. I get an error:
Incorrect syntax near the keyword 'insert'
The personal table is the primary table, and the owners table contains the foreign key.
How can I do the required in SQL Server?
I've got stuck-up here for the past two days...
I think you just have your syntax slightly off - you can definitely take values inserted into the main table and use the OUTPUT clause to insert those into a secondary table.
INSERT INTO dbo.personal(firstName)
OUTPUT INSERTED.pId INTO dbo.owners(pId)
VALUES('fn')
This will insert a new row into personal and set the column firstName to fn. From that insert, the inserted row's identity column pId is then inserted into the other table, owners, as that table's pId column.
See the MSDN documentation on the OUTPUT clause for more details - you can either output any of the inserted values to the console (e.g. SQL Server Mgmt Studio), or you can output those values into a temporary or a permanent table.
Update: as 'dradu' has pointed out - this approach won't work in your case here, since the column in the owners table is part of a FK constraint (I had missed that point from your question). So you'll need to use some other way to do this - probably outputting the necessary information into a temporary table / table variable in your code
Try the following steps
1) Apply transaction level on insertion
2) Get last inserted id using Scope_Identity() function.
When you apply transaction level it will lock your tables and other/same user cannot insert the value in this time.
try this it will work for you.
Since OUTPUT clause cannot be used directly because of the foreign key, you could add the generated IDs into a temporary table, then insert those values into the owners table:
BEGIN TRANSACTION
CREATE TABLE #ids(ID INT)
INSERT INTO personal(firstName)
OUTPUT inserted.pid INTO #ids
SELECT 'A'
UNION SELECT 'B'
INSERT INTO owners(pid)
SELECT ID FROM #ids
COMMIT TRANSACTION
SCOPE_IDENTITY will work too, but it's limited to one value.
You can use the SCOPE_IDENTITY() function to return the identity value inserted.
DECLARE #id INT
INSERT INTO [Personal] (Colums ....) VALUES (this, that, stuff)
SET #id = SCOPE_IDENTITY()
INSERT INTO [Owners] (Colums ....) VALUES (#id ....)
I think Your option is to use SCOPE_IDENTITY() but the other closest to your option is IDENT_CURRENT(‘tablename’) so I thought, I post detail of detail of other identity options as well which might help you to understand your choice and might helpful some other time
##IDENTITY
It returns the last IDENTITY value produced on a connection, regardless of the table that produced the value, and regardless of the
scope of the statement that produced the value.
SCOPE_IDENTITY() It returns the last IDENTITY value produced on
a connection and by a statement in the same scope, regardless of the
table that produced the value.
IDENT_CURRENT(‘tablename’) It returns the last IDENTITY value
produced in a table, regardless of the connection that created the
value, and regardless of the scope of the statement that produced the
value.
Here is one simple example of using SCOPE_IDENTITY() to get recent Identity Value
http://msdn.microsoft.com/en-us/library/ms190315.aspx

Resources