Updating a Table after some values are inserted into it in SQL Server 2008 - sql

I am trying to write a stored procedure in SQL Server 2008 which updates a table after some values are inserted into the table.
My stored procedure takes the values from a DMV and stores them in a table. In the same procedure after insert query, I have written an update query for the same table.
Insert results are populated fine, but the results of updates are getting lost.
But when I try to do only inserts in the stored procedure and I execute the update query manually everything is fine.
Why it is happening like this?

there should not be a problem in this.
below code working as expected.
create procedure dbo.test
as
begin
create table #temp (
name varchar(100) ,
id int
)
insert #temp
select name ,
id
from master..sysobjects
update #temp
set name='ALL Same'
from #temp
select * from #temp
drop table #temp
end
go

Best approach is to use Trigger, sample of AFTER UPDATE trigger is below:
ALTER TRIGGER [dbo].[tr_MyTriggerName]
ON [dbo].[MyTableName] AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
--if MyColumnName is updated the do..
IF UPDATE (MyColumnName)
BEGIN
UPDATE MyTableName
SET AnotherColumnInMyTable = someValue
FROM MyTableName
INNER JOIN Inserted
ON MyTableName.PrimaryKeyColumn = Inserted.PrimaryKeyColumn
END
END

Related

Inserting output parameters from stored procedure directly

I have a stored procedure that returns a pair of output parameters - the ID and the computed value. Is it possible to use a trigger with an insert statement, that inserts those two values directly? Something like this
CREATE TRIGGER Trig_FirstTable ON SecondTable AFTER UPDATE
AS
BEGIN
INSERT INTO FirstTable (OtherID, OtherValue)
VALUES (#otherID, #otherValue)
FROM StoredProcedure inserted.ID, inserted.Value, #otherID OUTPUT, #otherValue OUTPUT
END
According to the MSDN documentation you can use INSERT into with EXEC.
They give the following example:
--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales
But I think your stored procedure needs a SELECT statement to return the data instead of only filling the output parameters.
You can insert from SP like that:
drop procedure uspTest
GO
create procedure uspTest
AS
select 1 as id, 'x' as val
union all
select 2,'y'
GO
drop table #temp
GO
create table #temp (
id int,
val char(1)
)
GO
insert into #temp (id,val)
EXECUTE uspTest
GO
select
*
from #temp
But you cannot select a subset of columns, so this method will obviously fail if you add more outputs to your SP in the future:
insert into #temp (id)
EXECUTE uspTest
Another way is to store SP results in variables, and then use them for insert.

How to fire trigger after every insert in sql server table automatically?

I am new to SQL Server triggers. I am facing a problem recently that I have two tables named tbl_Item and tbl_changePrice. I want to update tbl_Item when tbl_changeprice is inserted new row. With this new row name same date data will be updated in tbl_item table.
Here is my trigger what is tried by me for updating the table:
Alter TRIGGER trgAfterInsert ON [dbo].[tbl_changePrice]
After insert
AS
declare #itemname int;
declare #saleprice decimal(18,2);
declare #buyprice decimal(18,2);
select #itemname=i.name from inserted i;
select #saleprice=i.saleprice from inserted i;
select #buyprice=i.pprice from inserted i;
update tbl_Item set sellingPrice= #saleprice, buyingPrice= #buyprice where name= #itemname
PRINT 'AFTER INSERT trigger fired.'
GO
To handle multiple rows being inserted at once - you need to rewrite your trigger to be able to deal with multiple rows in Inserted - something like this:
ALTER TRIGGER trgAfterInsert
ON [dbo].[tbl_changePrice]
AFTER INSERT
AS
UPDATE dbo.tbl_Item
SET sellingPrice = i.saleprice, buyingPrice = i.pprice
FROM Inserted i
WHERE tbl_Item.name = i.name
PRINT 'AFTER INSERT trigger fired.'
GO

How use inserted\deleted table in stored procedure?

I creating triggers for several tables. The triggers have same logic. I will want to use a common stored procedure.
But I don't know how work with inserted and deleted table.
example:
SET #FiledId = (SELECT FiledId FROM inserted)
begin tran
update table with (serializable) set DateVersion = GETDATE()
where FiledId = #FiledId
if ##rowcount = 0
begin
insert table (FiledId) values (#FiledId)
end
commit tran
You can use a table valued parameter to store the inserted / deleted values from triggers, and pass it across to the proc. e.g., if all you need in your proc is the UNIQUE FileID's:
CREATE TYPE FileIds AS TABLE
(
FileId INT
);
-- Create the proc to use the type as a TVP
CREATE PROC commonProc(#FileIds AS FileIds READONLY)
AS
BEGIN
UPDATE at
SET at.DateVersion = CURRENT_TIMESTAMP
FROM ATable at
JOIN #FileIds fi
ON at.FileID = fi.FileID;
END
And then pass the inserted / deleted ids from the trigger, e.g.:
CREATE TRIGGER MyTrigger ON SomeTable FOR INSERT
AS
BEGIN
DECLARE #FileIds FileIDs;
INSERT INTO #FileIds(FileID)
SELECT DISTINCT FileID FROM INSERTED;
EXEC commonProc #FileIds;
END;
You can
select * into #Inserted from inserted
select * into #Deleted from deleted
and then
use these two temp tables in your stored proc
The tables inserted and deleted are only available inside the trigger. You can only use them in run-time. They will then contain the affected rows.
Also, your code might not work as expected if there is not exactly one row inserted.

Insert results of execute(#QueryString) into a table while adding an extra column

I am writing a stored procedure that dynamically creates a SQL string, #SQLQuery. After I create this query, I need to execute the query and insert it into a table in the database while adding another column that specifies a unique ID for this particular insert. (Context: It is possible in this application that multiple groupings of data will be inserted into this table and I need to be able to differientiate between groupings at a later date. )
This issue is similar to this question except I am using Microsoft SQL Server 2008 instead of mysql. I have tried the solution there:
INSERT INTO data_table_name
EXECUTE(#SQLQuery), #SomeID
but MS SQL Server 2008 doesn't like that syntax.
Any ideas on how to do this in SQL Server 2008?
You can store query result in table variable and then read from that with extra column and write to final table
DECLARE #temp table (col1 int, col2 varchar(10), ....)
INSERT INTO #temp
EXEC(#SQLQuery)
INSERT INTO data_table_name
SELECT *, #SomeID FROM #temp
You can also append #SomeID in your dynamic sql string.
Example:
SET #SQLQuery = 'SELECT *,' + #SomeID + ' FROM ' + #tableNameVar
and then do this
INSERT INTO data_table_name
EXECUTE(#SQLQuery)
Since you mentioned you are doing this in a Stored Procedure, what I would suggest is for you to:
Execute the #SQLQuery first;
Upon successful execution of the #SQLQuery, insert the #SQLQuery to the table with the unique ID.
i.e.
EXEC sp_executesql #SQLQuery, #Param
IF ##ERROR <> 0
BEGIN
INSERT INTO TableA(Query)
VALUES(#SQLQuery)
END
You're better off designing TableA such that the ID will be an Identity so that a unique sequential ID is generated when you insert a record into that table.

Can a storeProcecdure insert fire Trigger?

SQL Server 2008
I have trigger defined on
TABLE_A for 'INSTEAD OF INSERT' and TABLE_B for 'INSTEAD OF INSERT'.
Both the triggers perform merge with the inserted table.
TABLE_A insert is done by user/code and is working well, trigger for insert is fired.
I have Stored procedure SP_1 inside TABLE_A TRIGGER.
SP_1 Inserts data from TABLE_A into TABLE_B based on some conditions.
But the problem is when the stored procedure (SP_1) is inserting data, the trigger on TABLE_B is not fired and the data is just inserted as it is.
So can stored procedure inserts fire triggers?
Pseudo-code
ALTER TRIGGER [dbo].[trgtable_AInsert] ON [dbo].[TABLE_A]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
.......
...........
..............
end
EXEC SP_1 #employee_id
end
ALTER TRIGGER [dbo].[trgtableB_Insert] ON [dbo].[TABLE_B]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
.......
...........
..............
end
end
ALTER PROCEDURE [dbo].[SP_1] #employeeid int
AS
BEGIN
BEGIN TRANSACTION
insert into TABLE_B
.......
...........
..............
from TABLE_A
where employee_ID is #employeeid
COMMIT TRANSACTION
END
Yes triggers can fired by stored procedure inserts!
But I think the problem is that you should try to use AFTER instead of INSTEAD OF triggers in this case. Becasue I can't see all of your code, but it is possible, that the insert is not done because you overrided it in the Instead Of triggers. With AFTER triggers you should have no problems with firing the second trigger.
This is too big for a comment, and needs formatting, so posting as an "answer".
Yes, triggers will fire in this case. Taking your example and slightly modifying it (note the warnings though):
create table Table_A (ID int not null)
go
create table Table_B (ID int not null)
GO
CREATE PROCEDURE [dbo].[SP_1] #employeeid int
AS
BEGIN
BEGIN TRANSACTION
insert into TABLE_B (ID)
SELECT ID from TABLE_A
where ID = #employeeid
COMMIT TRANSACTION
END
GO
Creating the triggers:
CREATE TRIGGER [dbo].[trgtable_AInsert] ON [dbo].[TABLE_A]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
into Table_A a
using inserted i on a.id = i.id
when not matched then insert (ID) values (i.id);
end
--Wrong code, just for example
declare #employee_id int
select #employee_id = ID from inserted --BAD CODE, Ignores multiple rows
EXEC SP_1 #employee_id
end
GO
CREATE TRIGGER [dbo].[trgtableB_Insert] ON [dbo].[TABLE_B]
Instead of INSERT
AS
BEGIN
SET NOCOUNT ON;
IF exists(SELECT * FROM INSERTED)
BEGIN
MERGE
into Table_B b
using inserted i on b.id = i.id
when not matched then insert (ID) values (i.id+5);
end
end
GO
And executing a trial insert into Table_A:
insert into Table_A (ID) values (1),(2)
select * from Table_B
On my machine, at the present time, I get a final result of a single row with the value "7". Others may run this sample and get the result "6", because triggers only run once per statement, rather than once per row. But as you can see, both triggers have fired.
As i previously mentioned in the comments #András Ottó
Merge
using(... = "column with possible null values" AND
... = ... AND
... = ...
)
of merge was not working correctly and the records were always inserted.
1 = 1 and E=E and NULL=NULL is not true. (of-course sql 101)
I have overlooked this column and did not place where clause properly to get rid of null values so ended up inserting all the time. Fixing that everything ended up working.
Thanks for the help Every1. Cheers
Apologies.
I'm not going to mark it answered because it is purely my mistake which was not fully mentioned in the question.