SQL Server: trigger updating a just inserted row - sql-server

I currently working with an old application that I don't own any source code but I really need to add some new logic to the app.
The only way I found to do it is to mess up with database data, and change whatever I need with a trigger.
I wrote the following trigger that should update 2 columns of a just inserted row:
CREATE TRIGGER addLoteInfo ON fi
FOR INSERT
AS
DECLARE
#loteN varchar(15),
#refN varchar(18),
#CientifN varchar(40),
#CaptureZ varchar(20)
declare MY_CURSOR cursor for
select
i.lote, i.ref
from inserted i
open MY_CURSOR
fetch next from MY_CURSORinto #loteN, #refN
while ##fetch_status = 0
begin
SELECT #CientifN = u_ncientif FROM SE where lote LIKE #loteN and ref LIKE #refN;
SELECT #CaptureZ = u_zcaptura FROM SE where lote LIKE #loteN and ref LIKE #refN;
UPDATE FI SET LNCIENT=#CientifN, LZCAP=#CaptureZ;
fetch next from CURSOR_TESTE into #loteN, #refN
end
close MY_CURSOR
deallocate MY_CURSOR
The problem is when a new registry is inserted, it seems it gets to a deadlock.
Its impossible to do what I'm trying to do?
Can you help me with another approach?

You need to use INSTEAD OF trigger if you want to modify newly inserted/updated record on the fly.

Related

t-sql INSTEAD OF deleting a row PRINT its id

Is it possible to make such a trigger that runs when you try to delete a row and prints something like this: "Attempting to delete row ROW_ID", instead of actually deleting the row?
UPD: Thanks. Worked for me:
GO
CREATE OR ALTER TRIGGER Trigger_2 ON Authors
INSTEAD OF DELETE
AS BEGIN
DECLARE #deleted_id INT;
DECLARE cursor_deleted CURSOR
FOR SELECT au_id FROM deleted;
OPEN cursor_deleted;
FETCH NEXT FROM cursor_deleted INTO #deleted_id;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT('Attempting to delete author ' + STR(#deleted_id));
FETCH NEXT FROM cursor_deleted INTO #deleted_id;
END;
CLOSE cursor_deleted;
DEALLOCATE cursor_deleted;
END;
GO
DELETE FROM Authors WHERE au_id BETWEEN 1 AND 10;
Yeah it is, and there are many approaches.
using a trigger you can either set the trigger to run after a deletion and u will have to use "ROLLBACK" to undo the deletion operation.
or just simply use INSTEAD OF where as the name suggests the trigger will replace the who deletion operation.
hope this helps in any way.
ps: after a deletion operation deleted data are stored in a Global table named "deleted" use to get any data or metaData that u need.
CREATE TRIGGER schema_name.trigger_name
ON table_name
// this trigger is executed instead of any deletion
INSTEAD OF DELETE
AS
BEGIN
// return the one to be deleted's id.
return deleted.id
END

SQL Server : update the same table after insert

I'm a beginner in SQL. I use Microsoft SQL Server and database for delivering bulk data from another system (different software on other pc).
I would like to update one column for just inserted rows. I created a trigger to update inserted rows, but this trigger do not update anything. It can update any other table, but update of the same table for rows have been just inserted do not work.
If I insert data directly in SSMS then it works - the same table where rows are inserted, are updated after insert. But data inserted from other system/server are not updated. Actually data are not even inserted. Have no idea why.
I was looking for any solution, found that MySQL cant update the same table what is being used for reading/writing. I don't know if the same logic is valid for SQL Server - but why manual insert works then?
This is my trigger:
ALTER trigger [cw].[mytrigger]
ON [cw].[TABLE1]
AFTER INSERT
AS
BEGIN
DECLARE #FBN nvarchar(10)
DECLARE db_cursor CURSOR FOR
SELECT FEEDBNO FROM inserted
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #FBN
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE cw.TABLE1
SET WCGroup = CASE
WHEN WCGroup = 'GROUP1' THEN 'GROUP_11'
WHEN WCGroup = 'GROUP2' THEN 'GROUP_22.'
WHERE FeedbackNo = #FBN
FETCH NEXT FROM db_cursor INTO #FBN
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
I appreciate any help or solution. Thanks.
UPDATE:
OK, solved another way. Problem was most likely ETL job runnig on source system. I created a new column in destination table and trigger insert required value into this column based on inserted data. Updating column used in ETL by trigger didn't work properly.
Thanks for anwers, I learned something new.
There's a few flaws with your trigger. Firstly, the cursor is a bad idea, so we should get rid of that; treat your data as it is; a dataset. Next, your CASE is missing an END, so you should be getting a syntax error. i believe this fixes the problem (You'll need to correct YourIDColumn to the appropriate column name):
ALTER TRIGGER cw.mytrigger ON cw.Table1
AFTER INSERT
AS BEGIN
UPDATE T1
SET WCGroup = CASE i.WCGroup WHEN 'GROUP1' THEN 'GROUP_11'
WHEN 'GROUP2' THEN 'GROUP_22.'
ELSE i.WCGroup END
FROM cw.table1 T1
JOIN inserted i ON T1.YourIDColumn = i.YourIDColumn;
END;

SQL Server a trigger to work on multiple rows updated

I have a problem with trigger which I use for procedure implementation. I use inserted table to collect all rows which user updated and procure procedure. But procedure repeat for ech row separately. How to handle this?
my trigger:
ALTER TRIGGER [dbo].[FormUpdate]
ON [dbo].[FORM]
For UPDATE
AS
BEGIN
SET NOCOUNT ON;
select * into #inserted from (
SELECT i.* from FORM gw
inner join inserted i on gw.FORMID = i.FORMID) t
WHERE t.PREPARING <> 0
IF (SELECT COUNT(*) FROM #inserted) > 0
BEGIN
UPDATE GW
SET PREPARING = 0
FROM FORM GW
INNER JOIN #inserted on GW.FORMID = #inserted.FORMID
EXEC dbo.PREPARING_OF_THE_FORM
END
END
I may be way off but i think i am pretty close.
As it looks right now the Form table is updated and then the stored procedure runs. I am guessing the stored procedure runs some work on the form table. If you want to run it on every row it looks like (i hate to say it) you need a CURSOR.
You will need to create a cursor from your first select something like
select * into #inserted from (
SELECT i.* from FORM gw
inner join inserted i on gw.FORMID = i.FORMID) t
WHERE t.PREPARING <> 0
DECLARE CURSOR inserted_Cursor
FOR
SELECT *
FROM #inserted
OPEN inserted_cursor
FETCH NEXT FROM inserted_cursor
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE GW
SET PREPARING = 0
FROM FORM GW
INNER JOIN #inserted on GW.FORMID = #inserted.FORMID
EXEC dbo.PREPARING_OF_THE_FORM
FETCH NEXT FROM inserted_cursor
END
CLOSE inserted_cursor
DEALLOCATE inserted_Cursor
I haven't had a chance to test this so it may take some fiddling to get it to run. I am not sure what the stored procedure is doing but you will need to make sure it can handle one record at a time. It may be best to not use the stored procedure and just write out the code to ensure it can handle the one row at a time.
Also keep in mind there are better ways to do this but with your specific application and without knowing the architecture this is what i think the best solution for you.

SQL Server - Triggers & Cursors - For Each Inserted Row, Update an Associated Value on Another Table

For a homework assignment, I'm trying to build a trigger that allows for multiple inserts/updates/deletes by utilizing a cursor. We have to use a cursor in order to practice the syntax. We know that there are very few practical scenarios for cursors in a production environment.
Here's what I'm trying to accomplish:
For each row inserted into the TAL_ORDER_LINE table, update the ON_HAND value in the TAL_ITEM table by subtracting the NUM_ORDERED value from the stored ON_HAND value.
Table Structure:
Current Query:
ALTER TRIGGER update_on_hand
ON TAL_ORDER_LINE
AFTER INSERT AS
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM inserted
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
UPDATE TAL_ITEM
SET ON_HAND = ON_HAND - #vNumOrdered
WHERE ITEM_NUM = #vItemNum
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
My Insert Query:
INSERT INTO TAL_ORDER_LINE (ORDER_NUM, ITEM_NUM, NUM_ORDERED, QUOTED_PRICE)
VALUES (51626, 'KL78', 10, 10.95), (51626, 'DR67', 10, 29.95)
It runs successfully, but does not affect the ON_HAND value. I think the biggest problem is that I'm struggling to understand cursor syntax, especially the INTO clause in the FETCH statement and how data from the 'inserted' table is passed into the cursor. What do I need to know to get this to work? Thanks in advance!
Your problem is likely due to this:
DECLARE #vItemNum as char
it is HIGHLY unlikely that the ItemNum column is a single character. For future reference, you should always verify that you variable definitions are consistent with the values you expect to store in them. And as has been hinted - you will get better answers by posting a complete script rather than a picture.
Big question,how you gonna debug ?
Is On_Hand col NULL , then do this isnull(on_Hand,0)
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM TAL_ORDER_LINE
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
--UPDATE TAL_ITEM
--SET ON_HAND = ON_HAND - #vNumOrdered
--WHERE ITEM_NUM = #vItemNum
print #vItemNum
print vNumOrdered
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
Try this :
ALTER TRIGGER update_on_hand ON TAL_ORDER_LINE
FOR INSERT AS
BEGIN
UPDATE TI
SET TI.ON_HAND = TI.ON_HAND - I.NUM_ORDERED
TAL_ITEM TI INNER JOIN
INSERTED I ON I.ITEM_NUM = TI.ITEM_NUM
END
Changed Trigger to FOR INSERT Trigger
Removed Cursor
Note: NOT Tested. ( If you post the sql scripts for create table + sample inserts I can give it a try )

SQL cursor works but db doesn't save changes

I have a table which has undesired characters(Ý) and I want to replace it with "I". Before I have tried that code for another column name and it worked perfect. But now while debuging I can see it fixes the rows but at the end db has no change... This is my code below:
DECLARE #CARI_NAME varchar(100)
DECLARE CRS_FixCariNameCURSOR FOR
SELECT CARI_NAME FROM TBLCASABIT
OPEN CRS_CariIsimDuzelt
FETCH NEXT FROM CRS_FixCariNameINTO #CARI_NAME
WHILE ##FETCH_STATUS=0
BEGIN
IF #CARI_NAME LIKE '%Ý%'
UPDATE TBLCASABIT SET #CARI_NAME = REPLACE(#CARI_NAME ,'Ý','I')
WHERE CURRENT OF CRS_FixCariName
FETCH NEXT FROM CRS_FixCariNameINTO #CARI_NAME
END
CLOSE CRS_FixCariName
DEALLOCATE CRS_FixCariName
with UPDATE TBLCASABIT SET #CARI_NAME = REPLACE(#CARI_NAME ,'Ý','I')
you update the variable and not the column!
use:
UPDATE TBLCASABIT SET CARI_NAME = REPLACE(#CARI_NAME ,'Ý','I')
if the column you want to update is called CARI_NAME
But what's more - Why do you even use a cursor here?
Simple Update does the same work more efficient (correct me if i am wrong):
UPDATE TBLCASABIT
SET CARI_NAME = REPLACE(CARI_NAME ,'Ý','I')
WHERE CARI_NAME LIKE '%Ý%'

Resources