Updating the table in a trigger written in sql server - sql-server

I am trying to create a trigger which is triggered when an insert, delete happens in a table 'Abschaetzung_has_Varianten' and updates a table called 'Flag'. I need to select an ID from the same table to update the Flag table. Is the syntax wrong in writing the SELECT of the ID? I don't seem to get the #abschID from the select. Could anyone help me in this. Thank you.
CREATE TRIGGER trig_update_flag on [Abschaetzung_has_Varianten]
after insert, delete
As
Begin
DECLARE #x INT;
DECLARE #abschID INT;
DECLARE #value INT;
SELECT #value = 1;
SELECT #abschID = (SELECT TOP 1 Abschaetzung_ID FROM Abschaetzung_has_Varianten ORDER BY Abschaetzung_ID DESC);
SELECT #x = Count(*) FROM Flag WHERE AbschaetzID = #abschID
If #x > 0
Begin
UPDATE Flag Set [Flag] = #value WHERE AbschaetzID = #abschID;
end
end

Your code should be more like this:
CREATE TRIGGER trig_update_flag on [Abschaetzung_has_Varianten]
after insert, delete
as
begin
UPDATE Flag Set [Flag] = 1
WHERE AbschaetzID IN (SELECT DISTINCT Abschaetzung_ID FROM INSERTED)
UPDATE Flag Set [Flag] = 1
WHERE AbschaetzID IN (SELECT DISTINCT Abschaetzung_ID FROM DELETED)
end
INSERTED is a special trigger pseudo table that contains all of the updated or inserted records.
DELETED is a special trigger pseudo table that contains all of the deleted records.
This table may contain many records for one invocation of the trigger.
The code above is not the most efficient and may not suit your exact requirements but hopefully you get the idea.

Related

SQL Trigger not updating field

When i select a value in one table, the same value must populate the other table.
For example:
Please see image attached:
The problem i am having is when i update the first field stage (left hand side), to say Stage2, the uStage field stays the same.. It should update to Stage2 as well..
The Ustage table has the same stage values as the Stage table so I know it needs to select the corresponding Value however i have tried all sorts to get this to work but it doesnt want to update:
Here is my Trigger code:
USE [SKY]
GO
/****** Object: Trigger [dbo].[SetIT] Script Date: 2018/10/04 19:52:06 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[SetIT] ON [dbo].[AMGR_Opportunity_Tbl]
AFTER INSERT
AS
DECLARE #RecordId int
DECLARE #Stage varchar(750)
Declare #ID int
begin
--check to see if we have any records in the inserted set
IF EXISTS( SELECT * FROM inserted ) BEGIN
--set up the cursor that we use to iterate over the recordset
DECLARE I CURSOR LOCAL FAST_FORWARD FOR
SELECT Record_Id FROM Inserted;
OPEN I
FETCH NEXT FROM I INTO #RecordId;
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #Stage = STAGE FROM STAGE WHERE ID = #ID;
--insert the UDF value
INSERT INTO O_Ustage(Client_id,Contact_Number,O_Ustage)
SELECT Opp_Id, 0, #Stage
FROM inserted WHERE Record_Id = #RecordId AND Opp_Type = 0;
--update the current stage
UPDATE stage set stage=#stage WHERE
ID=#ID;
FETCH NEXT FROM I INTO #RecordId;
END
CLOSE I
DEALLOCATE I
END
END
GO
Please assist in helping me figure out how to update the USTAGE field.
Below is the data that is in the Stage table
If i change the field 'Stage' below, then 'Ustage' also needs to change.. At the moment it is not doing it:
The opportunity table has 50 columns and stage table 2 columns.
When I change the stage on the opportunity table to Stage2 then the Ustage value must also change to Stage2.. Both values need to correspond
Your trigger code has a lot of problems, but here's one that will definitely cause it not to work:
SELECT #Stage = STAGE FROM STAGE WHERE ID = #ID;
Prior to that line of code, you never populate #ID, so it's value will be NULL. Therefore you will get NULL for #Stage, which is what you later insert into the O_UStage column.
Maybe you meant to use #RecordId on that line instead of #ID?

MSSQL Database Table Trigger not inserting records into another table after INSERT/UPDATE event

I am working on a MSSQL Database (for a program called Sage 200). There are many tables in the database, however, I want to be notified of changes (new record inserted or existing record updated) via Trigger on a specific table.
I also want to support multiple rows on this table being updated at same time also.
When a record is inserted or updated, I want to take a specific field from the table and insert/update another table with that field's value.
So, to put it into perspective; the trigger looks like this:
CREATE TRIGGER [dbo].[IC_CustomerLocationChanges] ON [dbo].[SLCustomerLocation]
AFTER INSERT,UPDATE
AS
BEGIN
SELECT RowNum = ROW_NUMBER() OVER(ORDER BY SLCustomerAccountID) , SLCustomerAccountID
INTO #CustomerLocationChanges
FROM INSERTED;
DECLARE #MaxRownum INT;
SET #MaxRownum = (SELECT MAX(RowNum) FROM #CustomerLocationChanges);
DECLARE #Iter INT;
SET #Iter = (SELECT MIN(RowNum) FROM #CustomerLocationChanges);
WHILE #Iter <= #MaxRownum
BEGIN
-- Get Customer account Id
DECLARE #SLCustomerAccountID INT = (SELECT SLCustomerAccountID FROM #CustomerLocationChanges WHERE RowNum = #Iter);
-- Check If Customer Doesn't Already Exist In Queue Table
IF ((SELECT COUNT(*) FROM IC_CustomerUpdates WITH (NOLOCK) WHERE SLCustomerAccountID = #SLCustomerAccountID) > 0)
BEGIN
-- Insert new record
print 'Insert [CustomerCreate] Queue Entry | SLCustomerAccountID : ' + CAST(#SLCustomerAccountID AS VARCHAR(255));
INSERT INTO IC_CustomerUpdates (SLCustomerAccountID, Synced) VALUES
(#SLCustomerAccountID, 0);
END
ELSE
BEGIN
-- Update existing record
print 'Update [CustomerCreate] Queue Entry | SLCustomerAccountID : ' + CAST(#SLCustomerAccountID AS VARCHAR(255));
UPDATE IC_CustomerUpdates SET Synced = 0
WHERE SLCustomerAccountID = #SLCustomerAccountID;
END
SET #Iter = #Iter + 1;
END
DROP TABLE #CustomerLocationChanges;
END
GO
To test this, I ran the following query:
update SLCustomerLocation SET AddressLine2 = AddressLine2 + ' test'
where SLCustomerAccountID = 1019
select * from IC_CustomerUpdates
This returns no rows from my IC_CustomerUpdates:
This is what I see in the message window:
This means the trigger hasn't inserted a record into my queue table. Any ideas what might be wrong?
#Lamak looks to be correct; stumbled on this a bit late but maybe this info will help others.
Sicon have developed a 3rd party add-on that helps audit changes. This might cover what you need.
Most integrations to Sage 200 use the OpLock field in each table to determine the last edit date.
SLCustomerLocation table can hold multiple records for a single SLCustomerAccountID so you might need to take this into consideration with your script.

how can I create a trigger in SQL Server to update after insert in a table

I created a trigger that after insert must update the table inserted:
alter trigger DispararInsertFactura1
on FacturaCabecera
after insert
as
BEGIN
Declare #numfac int;
select #numfac = NumFactura
FROM FacturaCabecera
WHERE id = (SELECT max(id) from FacturaCabecera);
update FacturaCabecera
set NumFactura=#numfac+1
where Id = (SELECT Id FROM INSERTED);
END
GO
But doesn't work, Did I make a mistake?
It is generally not allowed for a trigger to start a separate access to the same table it is defined on. The table is right smack in the middle of being altered (otherwise referred to as mutating).
"After" triggers are good for audit-type actions. Inserting an entry into a different table to describe the action that just took place.
"Before" triggers are good for verifying and possible altering the data stream before it goes to the table. This is what you want to do.
Unfortunately, SQL Server does not have "Before" triggers. It does, however, allow "Instead Of" triggers on tables. These triggers are not executed as part of the DML operation but before it begins. As the name implies, the trigger is executed in lieu of the DML operation. The trigger itself must initiate the operation or nothing happens. Defining an "Instead Of" trigger that does nothing is a good way to render a table or view read-only.
alter trigger DispararInsertFactura1
on FacturaCabecera
instead of insert as
declare #numfac int;
select Top 1 #numfac = NumFactura
from FacturaCabecera
order by id desc;
insert into FacturaCabecera( ..., NumFactura, ...)
select ..., IsNull( #numfac, 0 ) + 1, ...
from Inserted;
Notice that the trigger itself must execute the Insert statement, allowing it to alter what is being inserted.
I was thinking in this and I found the mistake, I didn't realize that the MAX number always would be a value NULL because the trigger will updated after of inserted in the table, (the value is NULL when I insert) so I changed this:
select #numfac = NumFactura
FROM Factura Cabecera
WHERE id = (SELECT max(id)
from Factura Cabecera);
for this that give me the number max second:
SELECT #numfac = NumFactura FROM FacturaCabecera WHERE ID = (SELECT MIN(id)
FROM (SELECT DISTINCT TOP (2) id FROM FacturaCabecera where
tipofactura='1' ORDER BY id DESC) T);
Thanks for you help
ALTER TRIGGER DispararInsertFactura1
on FacturaCabecera
INSTEAD OF INSERT AS
DECLARE #numfac int;
SELECT TOP 1 #numfac = NumFactura
FROM FacturaCabecera
ORDER BY id DESC;
INSERT INTO FacturaCabecera( __ , NumFactura, __)
SELECT __ , IsNull( #numfac, 0 ) + 1, __
FROM Inserted;
Trying this

Ensuring table is empty before data migration in order to not add duplicates

When performing a data migration in tsql, how do we make sure the table is empty before we bring over the data in order to not add duplicates.
For example to see if a table exists we use:
if exists(select * from sys.objects where name='table name') drop table table name
go
What do we use to see if a table is populated or empty?
You can find out row count with select count(*), and then do a test on the return value.
if (select count(*) from dbo.YourTableName) > 0
begin
-- handle condition where there are rows
end
else
begin
-- handle condition where there are no rows of data
end;
go
Do you need to KNOW the table was populated?
You could do a
DELETE FROM yourtable
as a matter of course
To delete ONLY if the table is not empty, try
declare #tablecount int;
select #tablecount = count(*) from yourtable
if #tablecount > 0
begin
delete from yourtable
end

After Update Triggers and batch updates

I have the following trigger to avoid updating a certain column.
ALTER TRIGGER [dbo].[MyTrigger]
ON [dbo].[MyTable]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF UPDATE(SomeID)
BEGIN
DECLARE #id INT,
#newSomeID INT,
#currentSomeID INT
SELECT #id = ID, #newSomeID = SomeID
FROM inserted
SELECT #currentSomeID = SomeID
FROM deleted
WHERE ID = #id
IF (#newSomeID <> #currentSomeID)
BEGIN
RAISERROR ('cannot change SomeID (source = [MyTrigger])', 16, 1)
ROLLBACK TRAN
END
RETURN
END
END
Since i'm selecting from inserted and deleted, will this work if someone updates the table using a where clause that encapsulates multiple rows? In other words is it possible for the inserted and deleted table to contain more than one row within the scope of my trigger?
Thanks...
why not use an instead of update trigger and just join to INSERTED and push in all the columns except the one you don't want to update? your approach does not take in account that multiple rows can be affected by an single UPDATE statement.
try something like this:
ALTER TRIGGER [dbo].[MyTrigger]
ON [dbo].[MyTable]
INSTEAD OF UPDATE
AS
BEGIN
UPDATE m
SET col1=INSERTED.col1
,col2=INSERTED.col2
,col4=INSERTED.col4
FROM [dbo].[MyTable] m
INNER JOIN INSERTED i ON m.PK=i.PK
END
you could also try something like this:
ALTER TRIGGER [dbo].[MyTrigger]
ON [dbo].[MyTable]
AFTER UPDATE
AS
BEGIN
IF EXISTS(SELECT 1 FROM INSERTED i INNER JOIN DELETED d ON i.PK=d.PK WHERE i.SomeID!=d.SomeID OR (i.SomeID IS NULL AND d.SomeID IS NOT NULL) OR (d.SomeID IS NULL AND i.SomeID IS NOT NULL))
BEGIN
RAISERROR ('cannot change SomeID (source = [MyTrigger])', 16, 1)
ROLLBACK TRAN
RETURN
END
END
This will work for multiple row updates. Also, if the "SomeID" is NOT NULL you can remove the two OR conditions in the IF EXISTS
You need to define a cursor in trigger and get all affected records in cursor and then process it.

Resources