sql anywhere trigger needs parameter - sqlanywhere

I had already found a fiew questions about triggers and parameters but no single one could solve my problem... the only thing I know is that its not good if triggers need parameters.
but I have 2 tables...e.g.
color object
====== ======
red pencil
green knife
blue pencil
yellow pencil
red knife
object count
====== =====
pencil 3
knife 2
And I have a procedure which deletes for example the red pencil.
Now I want to make a trigger who decreases the number of pencils in the second table about one.
Respectively if i delete a knife the number of knifes should be decreased.
But now I have to say the trigger which object I have deleted.
How I can make this?... or is it better if I use instead the trigger a procedure which is called by the procedure which deletes the object?
thank you

ty #SEFL
the code for sql anywhere is a bit different but it is the same principle.
Here is the code that works for me:
ALTER TRIGGER "deleteObject" AFTER DELETE
ORDER 1 ON "DBA"."objects"
REFERENCING OLD AS oldData
FOR EACH ROW
BEGIN
UPDATE summary
SET count = count - 1
WHERE object = oldData.object
END
here you access the deleted row with REFERENCING OLD AS oldData and then with oldData.object

Whenever you use a trigger to delete a row, most of the information in that row will be stored in a special table called "deleted" (certain data types such as ntext, text, and image aren't). But for your purposes, this should work.
Declare #Object nvarchar (50)
Select #Object = [Object] from deleted
Update YourSecondTable set [Count] -= 1 where [Object] = #Object
Adjust as needed. Make sure you only call this trigger on delete and not update, since update also copies data to the deleted table.
https://www.mssqltips.com/sqlservertip/2342/understanding-sql-server-inserted-and-deleted-tables-for-dml-triggers/ <-- general overview FYI.

Related

PostgreSQL best way to model position within scope of foreign key

I have boxes that contain books. The books table has a foreign key called "box_id", referencing the "id" of the box to which it belongs. I need a way to keep track of the relative position of each book within its box. A book can be removed from its box regardless of its position inside the box, but when a book is put into a box, it always goes in last. A book can be moved from one box to another. The order of books inside a box cannot be changed. What's the best way to model this? I prefer not to have a third table.
Put a sort_order column in the books table and use that in an ORDER BY clause when you query the books in a box.
You would update the sort_order every time you move a book from one box to another (or, put it in a box the first time) with a value larger than the other sort_order values in that box - or, for simplicity, with a value larger than all sort_order values in the entire table. For that, you can use a sequence or the current_time() (assuming you don't move multiple books into the same box in the same transaction). The update can be done either by the client code or using an ON INSERT/UPDATE trigger.
The normalized way would be to create a third table including box_id, book_id and book_position_in_box columns.
A denormalized way can be to create a book_id_array column in table box because the array types keep the order of the items in the arrays.
Then you can automatically update this array type column by trigger functions ON INSERT, ON UPDATE, ON DELETE defined on table books, like :
CREATE FUNCTION box_insert_update() RETURNS TRIGGER LANGUAGE plpgsql AS
$$
BEGIN
UPDATE box
SET book_id_array = book_id_array || array[NEW.id] -- book added at the last place in the NEW box
WHERE id = NEW.box_id ;
RETURN NEW ;
END ;
$$ ;
CREATE TRIGGER box_insert_update BEFORE INSERT OR UPDATE ON book
FOR EACH ROW EXECUTE FUNCTION box_insert_update() ;
CREATE FUNCTION box_update_delete() RETURNS TRIGGER LANGUAGE plpgsql AS
$$
BEGIN
UPDATE box
SET book_id_array = array_remove(book_id_array,OLD.id) -- book is removed from the OLD box with no gap
WHERE id = OLD.box_id ;
RETURN OLD ;
END ;
$$ ;
CREATE TRIGGER box_update_delete AFTER UPDATE OR DELETE ON book
FOR EACH ROW EXECUTE FUNCTION box_update_delete() ;
Full test sample & result in dbfiddle.

Is INSTEAD OF UPDATE trigger the best option

I have to check when a table is inserted to/updated to see if a column value exists for the same HotelID and different RoomNo in the same table. I'm thinking that an INSTEAD OF trigger on the table would be a good option, but I read that it's a bad idea to update/insert the table the trigger executes on inside the trigger and you should create the trigger on a view instead (which raises more questions for me)
Is it ok to create a trigger like this? Is there a better option?
CREATE TRIGGER dbo.tgr_tblInterfaceRoomMappingUpsert
ON dbo.tblInterfaceRoomMapping
INSTEAD OF INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #txtRoomNo nvarchar(20)
SELECT #txtRoomNo = Sonifi_RoomNo
FROM dbo.tblInterfaceRoomMapping r
INNER JOIN INSERTED i
ON r.iHotelID = i.iHotelID
AND r.Sonifi_RoomNo = i.Sonifi_RoomNo
AND r.txtRoomNo <> i.txtRoomNo
IF #txtRoomNo IS NULL
BEGIN
-- Insert/update the record
END
ELSE
BEGIN
-- Raise error
END
END
GO
So it sounds like you only want 1 row per combo of HotelID and Sonifi_RoomNo.
CREATE UNIQUE INDEX UQ_dbo_tblInterfaceRoomMapping
ON dbo.tblInterfaceRoomMapping(HotelID,Sonifi_RoomNo)
Now if you try and put a second row with the same values, it will bark at you.
It's (usually) not okay to create a trigger like that.
Your trigger assumes a single row update or insert will only ever occur - is that guaranteed?
What will be the value of #txtRoomNo if multiple rows are inserted or updated in the same batch?
Eg, if an update is performed against the table resulting in 1 row with correct data and 1 row with incorrect data, how do you think your trigger would cope in that situation? Remember triggers fire once per insert/update, not per row.
Depending on your requirments you could keep the instead of trigger concept, however I would suggest a separate trigger for inserts and for updates.
In each you can then insert / update and include a where not exists clause to only allow valid inserts / updates, ignoring inserting or updating anything invalid.
I would avoid raising an error in the trigger, if you need to handle bad data you could also insert into some logging table with the reverse where exists logic and then handle separately.
Ultimately though, it would be best for the application to check if the roomNo is already used.

Updating an "Inserted" column inside my "Insert" Trigger - a little different

I have researched quite a bit but couldn't find what I wanted-
(I have shallow knowledge on TRIGGERS in SQL- pardon me!)
Qn: I have all the THREE Triggers on my table (Insert, Update & Delete)
In my AFTER INSERT Trigger: I need to "update" the "inserted" column
and I was using :
UPDATE Table_name
SET Column_name = #Input
(currently)
But I was requested to use something like:
UPDATE "Inserted.column_name"
SET Column_name = #Input
But this generally cannot happen as it throws me an error:
The logical tables INSERTED and DELETED cannot be updated
Can someone help me out please?
I have seen posts on using INSTEAD OF TRIGGER but that doesn't serve my purpose.. Thanks in advance! Appreciate your help!
You need to update the actual, underlying table - not the Inserted pseudo table....
You need to join the tables on the primary key, and then update your actual data table - something like
CREATE TRIGGER trg_Insert_Sample
ON dbo.YourTableName
AFTER INSERT
AS
UPDATE dbo.YourTableName
SET SomeColumn = i.SomeValue
FROM Inserted i
WHERE dbo.YourTableName.PrimaryKey = i.PrimaryKey
or something along those lines....
You also need to be aware that the trigger is called once per statement - not once per row - so if your INSERT statements inserts 10 rows at once (from e.g. a SELECT), your trigger is called once, and Inserted will contain 10 rows - so you need to make sure your trigger code is capable of handling this situation and is written in a proper, set-based manner (no SELECT #Value = SomeColumn FROM Inserted - that won't work!)

How do I make a trigger to update a column in another table?

So I am working on adding a last updated time to the database for my app's server. The idea is that it will record the time an update is applied to one of our trips and then the app can send a get request to figure out if it's got all of the correct up to date information.
I've added the column to our table, and provided the service for it all, and finally manage to get a trigger going to update the column every time a change is made to a trip in it's trip table. My problem now comes from the fact that the information that pertains to a trip is stored across a multitude of other tables as well (for instance, there are tables for the routes that make up a trip and the photos that a user can see on the trip, etc...) and if any of that data changes, then the trip's update time also needs to change. I can't for the life of me figure out how to set up the trigger so that when I change some route information, the last updated time for the trip(s) the route belongs to will be updated in it's table.
This is my trigger code as it stands now: it updates the trip table's last updated column when that trip's row is updated.
CREATE OR REPLACE FUNCTION record_update_time() RETURNS TRIGGER AS
$$
BEGIN
NEW.last_updated=now();
RETURN NEW;
END;
$$
LANGUAGE PLPGSQL;
CREATE TRIGGER update_entry_on_entry_change
BEFORE UPDATE ON mydatabase.trip FOR EACH ROW
EXECUTE PROCEDURE record_update_time();
--I used the next two queries just to test that the trigger works. It
--probably doesn't make a difference to you but I'll keep it here for reference
UPDATE mydatabase.trip
SET title='Sample New Title'
WHERE id = 2;
SELECT *
FROM mydatabase.trip
WHERE mydatabase.trip.id < 5;
Now I need it to update when the rows referencing the trip row with a foreign key get updated. Any ideas from someone more experienced with SQL triggers than I?
"mydatabase" is a remarkably unfortunate name for a schema.
The trigger function could look like this:
CREATE OR REPLACE FUNCTION trg_upaft_upd_trip()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
UPDATE mydatabase.trip t -- "mydatabase" = schema name (?!)
SET last_updated = now()
WHERE t.id = NEW.trip_id -- guessing column names
RETURN NULL; -- calling this AFTER UPDATE
END
$func$;
And needs to be used in a trigger on every related table (not on trip itself):
CREATE TRIGGER upaft_upd_trip
AFTER UPDATE ON mydatabase.trip_detail
FOR EACH ROW EXECUTE PROCEDURE trg_upaft_upd_trip();
You also need to cover INSERT and DELETE (and possibly COPY) on all sub-tables ...
This approach has many potential points of failure. As alternative, consider a query or view that computes the latest last_updated from sub-tables dynamically. If you update often this might be the superior approach.
If you rarely UPDATE and SELECT often, your first approach might pay.

Firebird,lock inside trigger

Lately I fight with Firebird server with several clients project.I can avoid problems with deadlock in my programming enveroment but I want to do some work in triggers.
Thanks to advices which I've got from StackOverflow I realy close to my goals but I can not find information about catch deadlock in trigger, wait until it unlock and continue trigger procedure.
Could someone give me link or advice how to face with it?
Siple trigger definition with update or insert inside it:
CREATE TRIGGER XYZ FOR TABLE_X ACTIVE AFTER UPDATE POSITION 0 AS
begin
UPDATE TABLE_X SET FIELD = 1 where contidion
end
How to avoid problem when the row I want to change is lock by other process?
Regards,
Artik
In your comments you say that you want to update the same row that the trigger fired for, in that case no deadlock can occur, as the current transaction already has the 'lock' on the row, so it is allowed to modify it again. However your approach is wrong. If you want to modify the content of the same row the trigger fired for, you should not use an AFTER UPDATE trigger, but a BEFORE UPDATE trigger and use the NEW trigger context variables to update one or more columns.
So you trigger should be something like:
CREATE TRIGGER XYZ FOR TABLE_X ACTIVE BEFORE UPDATE POSITION 0 AS
begin
IF condition THEN
NEW.FIELD = 1;
end