Avoid update trigger loop sql anywhere 12 - sql

Looks like in previous versions you could use ##nestlevel, but in ver 12 it always returns -1.
So how do you avoid update loops?
I'm trying to sync multiple connected contacts in the same table.
ALTER TRIGGER "Sync" AFTER UPDATE
ORDER 1 ON "Contact"
REFERENCING OLD AS oldRec NEW AS newRec
FOR EACH ROW
BEGIN
IF ##nestlevel = 1 THEN
UPDATE Contact set Title = newRec.Title
WHERE newRec.syncid = Contact.syncid;
END IF
END
This results

Related

Trigger in SQL causing error "Product_Reorder is not a recognized SET option"

CREATE OR ALTER TRIGGER CheckQuantity
ON dbo.Products
AFTER UPDATE
AS
BEGIN
UPDATE dbo.Products
SET Product_ReOrder = 1
FROM Inserted i
WHERE i.Product_ID = dbo.Products.Product_ID
AND i.Product_QOH < 5;
I am not getting a syntax error
syntax error near ;
This is referring to the ; at the end of the code.
Not 100% sure what you're trying to do - you're not giving us much to go on, either!
I'm assuming you mean you want to set a column called Product_ReOrder in your table to 1 if another column Product_QOH is less than 5 - correct?
In that case - use a trigger something like this:
CREATE OR ALTER TRIGGER CheckQuantity
ON dbo.Products
AFTER UPDATE
AS
BEGIN
UPDATE dbo.Products
SET Product_ReOrder = 1
FROM Inserted i
WHERE i.PrimaryKeyColumn = dbo.Products.PrimaryKeyColumn
AND i.Product_QOH < 5;
END
The trigger will fire after an UPDATE, and Inserted will contain all rows (can and will be multiple rows!) that have been updated - so I'm assuming you want to check the quantity on those rows.
I'm joining the base table (dbo.Products) to the Inserted pseudo table on the primary key column of your table (which we don't know what it is - so you need to adapt this as needed), and I'm setting the Product_ReOrder column to 1, if the Products_QOH value is less than 5.
Your line of code
Select #QOH = (select Product_QOH from inserted)
has a fatal flaw of assuming that only one row was updated - this might be the case sometimes - but you cannot rely on that! Your trigger must be capable of handling multiple rows being updated - because the trigger is called only once, even if 10 rows are updated with a command - and then Inserted will contain all those 10 updated rows. Doing such a select is dangerous - you'll get one arbitrary row, and you'll ignore all the rest of them ....
Is that what you're looking for?
I'm unclear what you were thinking when you wrote this code, or what template you were basing off, but there are many syntax errors.
It seems you probably want something like this:
The update() function only tells us if that column was present in the update statement, not if anything was actually changed.
We need to check if we are being called recursively, in order to bail out.
We also check if no rows have been changed at all, and bail out early
Note how inserted and deleted are compared to see if any rows actually changed. This also deals correctly with multiple rows.
We then need to rejoin Products in order to update it.
create or alter trigger CheckQuantity
on Products
after update
as
set nocount on;
if not(update(Products_QOH))
or TRIGGER_NESTLEVEL(##PROCID, 'AFTER', 'DML') > 1
or not exists (select 1 from inserted)
return; -- early bail-out
update p
set Product_ReOrder = 1
from Products p
join (
select i.YourPrimaryKey, i.Products_QOH
from inserted i
where i.Product_QOH < 5
except
select d.YourPrimaryKey, d.Products_QOH
from deleted d
) i on i.YourPrimaryKey = p.YourPrimaryKey;
However, I don't understand why you are using a trigger at all.
I strongly suggest you use a computed column for this instead:
ALTER TABLE Products
DROP COLUMN Product_ReOrder;
ALTER TABLE Products
ADD Product_ReOrder AS (CASE WHEN Product_QOH < 5 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END);

Update or otherwise create an entry in table

I want to update or create a new entry in a table with normal SQL (not MySQL).
My table has columns: T_ID, ITERATION, COMMENT
I know that I can update my table with:
UPDATE TABLE
SET ITERATION = ITERATION + 1
WHERE T_ID = 1;
But if no entry with T_ID = 1 exists I want to create an entry with ITERATION = 1 and T_ID = 1 and as COMMENT nothing.
Is this possible by using a normal SQL statement?
Is this possible by using a normal SQL statement?
No - there is no "standard" SQL construct for an "upsert" (or Merge) in one statement. Different SQL systems have implemented mechanism to perform an "update if exists" operation, such as MySQL's ON DUPLICATE KEY UPDATE or Oracle and SQL Server's MERGE syntax, but nothing in "standard" SQL.
You would want to do it in a stored procedure. Something like this where you're checking to see if anything exists where T_ID = 1. Then based off that conclusion you'll either update or insert.
BEGIN TRAN
IF EXISTS (SELECT * FROM table WHERE T_ID = 1)
BEGIN
UPDATE table SET ITERATION = ITERATION + 1 WHERE T_ID = 1
END
ELSE
BEGIN
INSERT INTO table (T_ID, ITERATION, COMMENT)
VALUES (1, 1, '')
END
COMMIT TRAN

Updating or deleting a sql table for non existent record

How does SQL behave and what does it return when I try updating or deleting a on existent record in the table. I checked running an update on a non existent record and the query basically runs, doesn't do anything and returns saying a no records were affected. However I wanted to understand how it works internally and what would the result variable hold after such queries.
It depends on the database but usually you can get the affected rows after update or insert.
If nothing is updated you will get 0 for the rowcount.
Pl SQL example:
declare
i number;
begin
update MyTable set status = 'someStatus' where name = 'someName';
i := sql%rowcount;
end;
T-SQL example:
UPDATE Table Set Column = 0 WHERE Column IS NULL
SELECT #RowCount = ##ROWCOUNT
How it works internaly depends on the database vendor.

Creating a trigger to update multiple records after insert sql server 2008

Well basically I need this trigger to work after a user inserts multiple records into the database. So that when an optionID of 0 is inserted and the IsoptionalID = 1, then set the OptionID = NULL
CREATE TRIGGER ThisDatabase
ON OtherTable
AFTER INSERT
AS
BEGIN
DECLARE #OPTIONID INT
SET #OPTIONID = OtherTable.OPTIONID
DECLARE #ISoptional INT
SET #ISoptional = OtherTable.ISoptional
CASE #optionID WHEN 0 and #ISoptional = 1 set update OtherTable set optionid = null end
END
I am not sure about the case itself either.
Thank you in advance
This depends on the key field(s) of the table, but SQL Server triggers always work on the entire data set being modified (Inserted, Updated, or Deleted). So the trigger would something more like:
CREATE TRIGGER ThisDatabase
ON OtherTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE ot
SET ot.OptionID = NULL
FROM OtherTable ot
INNER JOIN INSERTED ins
ON ins.KeyField = ot.KeyField
WHERE ins.OptionID = 0
AND ins.IsOptional = 1
END
The INSERTED table has the rows that were either Inserted or Updated (current version).
The DELETED table has the rows that were either Deleted or Updated (old version).
So, the INSERTED and DELETED tables are pre-filtered to only the changed records, but they are not updatable (since the event already happened due to this being an AFTER trigger and SQL Server not having a BEFORE trigger) so you need to do the UPDATE on the real table.
It isn't really clear what you want to do, but here's a skeleton. Just note:
Triggers are created on the table which is being affected (not an Other table)
You can certainly update another table as a consequence of a trigger. This is typically done through a join.
Use the inserted and deleted pseudo-tables to identify the record(s) which have been inserted, updated or deleted.
CREATE TRIGGER TR_TableBeingInsertedInto
ON TableBeingInsertedInto
AFTER INSERT
AS
BEGIN
UPDATE OtherTable
-- What you actually want to do here isn't clear to me
SET OtherTable.OPTIONID =
CASE i.OptionID
WHEN 0 THEN NULL
ELSE OtherTable.OPTIONID
END
FROM OtherTable
-- Inserted has the same schema as TableBeingInsertedInto
INNER JOIN INSERTED i
ON OtherTable.SomeCommonKey = i.SomeCommonKey;
END

How to refer to "New", "Old" row for Triggers in SQL server?

SO I'm new to SQL server from SQLite and I am used to using the New|Old keywords. I have seen that some people use the inserted value refer to a newly created row, but this would only apply on an insert and not an update. Howe can I get something like the New I use in this query?
create trigger ports_country_id_in_check
on [SISTEMA].Puerto
after insert, update
AS
BEGIN
update [SISTEMA].Puerto
set country_id = (select secuencia from [SISTEMA].Pais where codigo = New.pais_asociado)
where [SISTEMA].Puerto.secuencia = New.secuencia
end
Inserted also will also apply to update. One updated row will be seen as a deleted and an inserted row. So you can check both what was and what it is now.
create trigger ports_country_id_in_check
on [SISTEMA].Puerto
after insert, update
AS
BEGIN
Declare #pais_asociado, #secuencia int
select #pais_asociado = Puerto.pais_asociado, #secuencia = Puerto.secuencia
from Puerto join inserted
where Puerto.secuencia = inserted.secuencia
update [SISTEMA].Puerto
set country_id = (select secuencia from [SISTEMA].Pais where codigo = #pais_asociado)
where [SISTEMA].Puerto.secuencia = #secuencia
end