how to create a select trigger for sybase ase 12.5? - tsql

trigger usually is on delete, update, insert. It means update data.
I want to a trigger for access data. for example, when applying select on a table, then a trigger can be fired.
Is it possible to create a trigger on select for sybase ase 12.5?

This is trigger's statement from documentation:
create trigger [owner .]trigger_name
on [owner .]table_name
for {insert , update , delete}
as SQL_statements
as you can see, there is no option for select.
So it's not possible.

Related

PostgreSQL Trigger that updates table where original trigger runs from

I have two tables in this scenario. One is my "hot sync" table which is near-realtime bi-directional sync of data from my Salesforce Org to a Postgres table. As data changes in the source system (Salesforce), it updates that table on Postgres.
On this table in Postgres, I have a trigger that runs some logic. It basically checks to see if the record triggering it has a sent date that meets some business logic, copy that row into another schema/table to "archive" it.
This all works fine.
What I need to do however is once this row has been copied into the other table, I need to update the status of the record hot sync table. Since it is bi-directional, this will allow the data in Salesforce to reflect the changes I make from the Postgres side.
Can I place this update statement within the originating trigger or is this going to cause recursion issues?
CREATE FUNCTION salesforce.archivelogicfunc()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100
VOLATILE NOT LEAKPROOF
AS $BODY$ BEGIN
IF (DATE(NEW.et4ae5__datesent__c) < NOW() - INTERVAL '180 days'
AND DATE(NEW.et4ae5__datesent__c) > NOW() - INTERVAL '540 days')
THEN
INSERT INTO archive.individualemailresult__c
(dateopened__c,
numberoftotalclicks__c,
datebounced__c,
fromname__c,
hardbounce__c,
fromaddress__c,
softbounce__c,
name,
lastmodifieddate,
opened__c,
ownerid,
subjectline__c,
isdeleted,
contact__c,
systemmodstamp,
lastmodifiedbyid,
datesent__c,
dateunsubscribed__c,
createddate,
createdbyid,
lead__c,
tracking_as_of__c,
numberofuniqueclicks__c,
senddefinition__c,
mergeid__c,
triggeredsenddefinition__c,
sfid,
id,
_hc_lastop,
_hc_err,
isarchived)
VALUES
(NEW.et4ae5__dateopened__c,
NEW.et4ae5__numberoftotalclicks__c,
NEW.et4ae5__datebounced__c,
NEW.et4ae5__fromname__c,
NEW.et4ae5__hardbounce__c,
NEW.et4ae5__fromaddress__c,
NEW.et4ae5__softbounce__c,
NEW.name,
NEW.lastmodifieddate,
NEW.et4ae5__opened__c,
NEW.ownerid,
NEW.et4ae5__subjectline__c,
NEW.isdeleted,
NEW.et4ae5__contact__c,
NEW.systemmodstamp,
NEW.lastmodifiedbyid,
NEW.et4ae5__datesent__c,
NEW.et4ae5__dateunsubscribed__c,
NEW.createddate,
NEW.createdbyid,
NEW.et4ae5__lead__c,
NEW.et4ae5__tracking_as_of__c,
NEW.et4ae5__numberofuniqueclicks__c,
NEW.et4ae5__senddefinition__c,
NEW.et4ae5__mergeid__c,
NEW.et4ae5__triggeredsenddefinition__c,
NEW.sfid,
NEW.id,
NEW._hc_lastop,
NEW._hc_err,
NEW.isarchived__c)
ON CONFLICT (id)
DO NOTHING;
-- Update SF to reflect the archive
UPDATE salesforce."et4ae5__individualemailresult__c" SET isarchived__c = true, isdeleted = true WHERE id = NEW.id;
END IF;
RETURN NULL;
END;
$BODY$;
ALTER FUNCTION salesforce.archivelogicfunc()
OWNER TO ....;
My understanding is that the NEW.* is only going to contain the rows that caused the trigger to fire in the first place. Therefore if my trigger was fired for a single record, the update statement NEW.id should only update one record on the source table?
Trying to ensure the trigger isn't going to fire again with the update statement causing some recursive loop that I am not expecting.
My concern is:
Record is Updated
Trigger Fires and inserts record into an archive table
Update runs on the source table to update the record for the new.id
This update causes the trigger to run again. The insert would fail due to the on conflict, but the update would then run again, and again etc..
The original trigger is fired AFTER INSERT/UPDATE.
TRIGGER:
CREATE TRIGGER archivelogic_firetrigger
AFTER INSERT OR UPDATE
ON salesforce.et4ae5__individualemailresult__c
FOR EACH ROW
EXECUTE PROCEDURE salesforce.archivelogicfunc();
UPDATE:
I added a WHEN condition to my trigger. It appeared to work on a basic test, but willing to take any other advice if suggested.
CREATE TRIGGER archivelogic_firetrigger
AFTER INSERT OR UPDATE
ON salesforce.et4ae5__individualemailresult__c
FOR EACH ROW
WHEN (pg_trigger_depth() = 0) // <-- Added to prevent recursion
EXECUTE PROCEDURE salesforce.archivelogicfunc();
The easiest would be to make it a before trigger, and to replace the update by
NEW.isarchived__c = true;
NEW. isdeleted = true;
[...]
RETURN NEW;
Otherwise, you can filter the rows before running the trigger: it will be called only when isarchived__c and isdeleted have NOT changed (it may be dangerous though, just imagine someone updating ALL fields)
CREATE TRIGGER archivelogic_firetrigger
AFTER INSERT OR UPDATE
ON salesforce.et4ae5__individualemailresult__c
FOR EACH ROW
WHEN (NEW.isarchived__c IS NOT DISTINCT FROM OLD.isarchived__c
AND NEW.isdeleted IS NOT DISTINCT FROM OLD.isdeleted )
EXECUTE PROCEDURE salesforce.archivelogicfunc();

PgSQL log table update time

I've created the following table:
CREATE TABLE updates
(
"table" text,
last_update timestamp without time zone
)
I want to update it whenever any table is updated, the problem is I don't know how, could someone please help me turn this pseudocode into a trigger?
this = current table on whitch operation is performed
ON ALTER,INSERT,DELETE {
IF (SELECT COUNT(*) FROM updates where table = this) = 1
THEN
UPDATE updates SET last_update = timeofday()::timestamp WHERE `table`=this
ELSE
INSERT INTO updates VALUES (this,timeofday()::timestamp);
}
You need a trigger function that is called whenever one of your tables is "updated", assuming that you mean that an INSERT, UPDATE, or DELETE is successfully executed. That trigger function would look like this:
CREATE FUNCTION log_update() RETURNS trigger AS $$
BEGIN
UPDATE updates SET last_update = now() WHERE "table" = TG_TABLE_NAME;
IF NOT FOUND THEN
INSERT INTO updates VALUES (TG_TABLE_NAME, now());
END IF;
IF (TG_OP = 'DELETE') THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END; $$ LANGUAGE PLPGSQL;
Every table that has to be logged this way needs to have a trigger associated with it like this:
CREATE TRIGGER ZZZ_mytable_log_updates
AFTER INSERT OR UPDATE OR DELETE ON mytable
FOR EACH ROW EXECUTE PROCEDURE log_update();
A few comments:
Trigger functions are created with PL/PgSQL; see chapter 40 in the documentation. Trigger functions come with some automatic parameters such as TG_TABLE_NAME.
Don't use reserved words ("table" in your case) as column names. Actually, in this case you are better off using the oid of the table, with the associated TG_RELID automatic parameter. It takes up less storage, it is faster, and it avoids confusion between tables with the same name in different schemas of your database. You can use the pg_tables system catalog table to look up the table name from the oid.
You must return the proper value depending on the operation, or the operation may fail. INSERT and UPDATE operations need to have NEW returned; DELETE needs to have OLD returned.
The name of the trigger starts with "ZZZ" to make sure that it fires after any other triggers on the same table have succeeded (they are fired in alphabetical order). If a prior trigger fails, this trigger function will not be called, which is the proper behaviour because the insert, update or delete will not take place either.

Postgres audit trigger only fired by one row UPDATE

Hi I'm up to develop a simple audit trigger for postgresql server. According to this document, I pretty much understand how it works. But I want to record my activity only when the certain row is updated. Below is the code from the link. And it records when there is update no matter what row is updated.
IF (TG_OP = 'UPDATE') THEN
...
Please help me how to give a condition to above code. Thanks!
The trigger is written in PL/PgSQL. I strongly suggest you study the PL/PgSQL manual if you're going to modify PL/PgSQL code.
In triggers, the row data is in OLD and NEW (for UPDATE triggers). So you can do IF tests on that like anything else. E.g.:
IF (TG_OP = 'UPDATE') THEN
IF NEW."name" = 'name_to_audit' OR OLD."name" = 'name_to_audit' THEN
-- do audit commands
END IF;
END IF;
Both NEW and OLD are tested in case the name is being changed from/to the name of interest.
In this case you could instead change it to use a WHEN clause on the CREATE TRIGGER, so you never fire the trigger at all unless the conditions to audit are met. See the WHEN clause on triggers.
This is just a basic programming problem; you'll need to learn the programming language in order to use it.
See also the updated trigger for Pg 9.1.
Oh, and remember to think about NULL; remember NULL = 'anything' is NULL. Use IS DISTINCT FROM if you want to say "these things are equal, or are both null".
From Postgresql Docs:
CREATE TRIGGER log_update
AFTER UPDATE ON accounts
FOR EACH ROW
WHEN (OLD.* IS DISTINCT FROM NEW.*)
EXECUTE PROCEDURE log_account_update();
This only work for UPDATE on that table. For INSERT AND DELETE you can use same without WHERE query. Hope this help others.

Applying trigger on sqlite database in objective-c

How can I apply a trigger on my sqlite database using objective-c.
I want to apply trigger to check if a table has performed an insert operation.
Run a CREATE TRIGGER statement on it. You'll need to find some way to check the trigger fires, so if you e.g. make the trigger insert rows into another table, you can regularly check the table to see if it has new rows.
If you have a table named CSAppointment, the you can write:
ALTER TABLE "CSAppointment" ADD COLUMN "tableUid" INTEGER;
CREATE TRIGGER log_insert AFTER INSERT ON CSAppointment
BEGIN
INSERT INTO CSRowChanges(tableUId, rowUid, deleteFlag ) VALUES (NEW.tableUid, NEW.uid, 0 );
END;
CREATE TRIGGER log_update AFTER UPDATE ON CSAppointment
BEGIN
INSERT INTO CSRowChanges(tableUId, rowUid, deleteFlag) VALUES (NEW.tableUid, NEW.uid, 0) ;
END;
CREATE TRIGGER log_delete AFTER DELETE ON CSAppointment
BEGIN
INSERT INTO CSRowChanges(tableUId, rowUid, deleteFlag) VALUES (OLD.tableUid, OLD.uid, 1 ) ;
END;
This way you are adding triggers for insert, update and delete operations.
More information on here.

How do I cancel a Delete in SQL

I want to create a trigger to check what is being deleted against business rules and then cancel the deletion if needed. Any ideas?
The solution used the Instead of Delete trigger. The Rollback tran stopped the delete. I was afraid that I would have a cascade issue when I did the delete but that didn't seem to happen. Maybe a trigger cannot trigger itself.
Use an INSTEAD OF DELETE (see MSDN) trigger and decide within the trigger what you really want to do.
The solution used the Instead of Delete trigger. The Rollback tran stopped the delete. I was afraid that I would have a cascade issue when I did the delete but that did'nt seem to happen. Maybe a trigger cannot trigger itself. Anyhow, thanks all for your help.
ALTER TRIGGER [dbo].[tr_ValidateDeleteForAssignedCalls]
on [dbo].[CAL]
INSTEAD OF DELETE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #RecType VARCHAR(1)
DECLARE #UserID VARCHAR(8)
DECLARE #CreateBy VARCHAR(8)
DECLARE #RecID VARCHAR(20)
SELECT #RecType =(SELECT RecType FROM DELETED)
SELECT #UserID =(SELECT UserID FROM DELETED)
SELECT #CreateBy =(SELECT CreateBy FROM DELETED)
SELECT #RecID =(SELECT RecID FROM DELETED)
-- Check to see if the type is a Call and the item was created by a different user
IF #RECTYPE = 'C' and not (#USERID=#CREATEBY)
BEGIN
RAISERROR ('Cannot delete call.', 16, 1)
ROLLBACK TRAN
RETURN
END
-- Go ahead and do the update or some other business rules here
ELSE
Delete from CAL where RecID = #RecID
END
The trigger can roll back the current transaction, which will have the effect of cancelling the deletion. As the poster above also states, you can also use an instead of trigger.
According to MSDN documentation about INSTEAD OF DELETE triggers:
The deleted table sent to a DELETE
trigger contains an image of the rows
as they existed before the DELETE
statement was issued.
If I understand it correctly the DELETE is actually being executed. What am I missing?
Anyway, I don't understand why do you want to delete the records and if the business rules are not passed then undelete those records. I would have swear it should be easier to test if you pass the business rules before deleting the records.
And I would have said use a transaction, I haven't heard before about INSTEAD OF triggers.