Multiple triggers - tsql

Can we call trigger that contain invocation of multiple triggersw on a single button click event?
as there are two triggers as follows:
First fires after insertion:
CREATE TRIGGER trgAfterInsert ON [dbo].[Employee_Test]
FOR INSERT
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action varchar(100);
select #empid=i.Emp_ID from inserted i;
select #empname=i.Emp_Name from inserted i;
select #empsal=i.Emp_Sal from inserted i;
set #audit_action='Inserted Record -- After Insert Trigger.';
insert into Employee_Test_Audit
(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
values(#empid,#empname,#empsal,#audit_action,getdate());
PRINT 'AFTER INSERT trigger fired.'
GO
Second is for Login:
Alter TRIGGER user_confirmation ON ADMINISTRATOR
FOR INSERT
AS
declare #ID varchar(20);
declare #u_name varchar(20);
declare #u_id varchar(20);
set #u_id= (select u_password from ADMINISTRATOR where u_name=#u_name);
select #ID from Inserted I;
if(#ID=#u_id)
print'Login Successfull'
GO
I just want to call trgAfterInsert in user_confirmation trigger. Is it possible?

You cannot call triggers directly.Triggers will be automatically fired based on your DML statements.Nested triggers are allowed and you have to change database setting for that.
please see below link for detailed info.
https://msdn.microsoft.com/en-us/library/ms190739.aspx
DML statement on table A fires trigger a which in turns updates some table B causing trigger B to fire on that Table B
I dont think you have a need to for mutiple triggers,but rather call stored procs from button click event

Related

After insert trigger in postgres not working

i am creating a trigger that is supposed to be fired every time a new device is added in to the device table. Since the id in the table is auto incrementing i have set is so that the trigger is fired after the insert. The insertion works but the trigger is not being fired or atleast i am not seeing the data in the table that is supposed to receive the information.
the function
CREATE OR REPLACE function insertstagingdevice() returns trigger as $device$
DECLARE
begin
INSERT INTO postgres.staging_import_remote_access.device(device_id,
name, eui,
location)
VALUES(new.id,
new.name,
new.eui,
new.location);
RETURN NEW;
END
$device$ language plpgsql;
The trigger
CREATE TRIGGER insertionIntoDevice
after INSERT
ON postgres.public.device
FOR EACH row
EXECUTE PROCEDURE insertstagingdevice();
Is there something i am overseeing ?
The code is correct. there was an error elswehere. Thanks for your help

PostgreSQL triggers and temporary table

I have created an before update and after update trigger on a postgresql db table.
There is a requirement to preserve historical record and at the same time create a new record for the said data. Old record is to be marked as archived.
I was planning on using temporary table to keep track of the NEW values and reset the NEW values such that it is marked as archived.
In my after update trigger I would read the data from the temporary table, and create a brand new active record.
My problem is temporary table created in before update trigger is not visible to after update trigger. Moreover I cannot even pass on any argument (of type record) to the after update trigger as it is not allowed.
I have already achieved the desired result in Oracle db, using Global Temporary table, but having a tough time in PostgreSQL.
Here is the sample code for before update trigger function:
CREATE OR REPLACE FUNCTION trigger_fct_trig_trk_beforeupdate()
RETURNS trigger AS
$BODY$
DECLARE
some variable declarations;
BEGIN
Drop table IF EXISTS track_tmp_test;
CREATE TEMPORARY TABLE track_tmp_test(
...
);
Insert into track_tmp_test (........)
values(NEW., NEW..., NEW.., NEW...);
NEW... := OLD...;
NEW... := OLD.... ;
NEW... := OLD...;
Mark the NEW.status : = 'archived';
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE TRIGGER trig_trk_test_beforeupdate
BEFORE UPDATE ON test
FOR EACH ROW EXECUTE PROCEDURE trigger_fct_trig_trk_beforeupdate() ;
NOW the after UPDATE trigger function:
CREATE OR REPLACE FUNCTION trigger_fct_trg_trk_afterupdate()
RETURNS trigger AS
$BODY$
DECLARE
some variables;
-- insert into original table the data from temporary that was inserted in before update trigger
INSERT into TEST (....)
select ....
from track_tmp_test ;
-- delete data from temporary table after insert
delete from track_tmp_test ;
EXCEPTION
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Is there a way that after update trigger can access the temporary table created in before update trigger function?
I cannot have a permanent table hold he values, as trigger can be fired by many users updating the data in the table.
There is no problem with access to temporary table from triggers, and following code working without issue (on PostgreSQL 9.4):
CREATE OR REPLACE FUNCTION public.f1()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
drop table if exists bubu;
create temp table bubu(a int);
insert into bubu values(10);
return new;
end
$function$
CREATE OR REPLACE FUNCTION public.f2()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
declare r record;
begin
for r in select * from bubu
loop
raise notice '%', r;
end loop;
return null;
end
$function$
create trigger xx
before insert on omega
for each row execute procedure f1();
create trigger yy
after insert on omega
for each row execute procedure f2();
postgres=# insert into omega values(333);
NOTICE: (10)
INSERT 0 1
So I am sure, so your problem will not be in access to temporary tables. It works well. There can be a issue on some 8.2, 8.3 and older with invalid plans due reference on dropped objects. Isn't it your problem?
I can say, so your design is wrong - there is not any reason, why you have to use a temp table. Same job you can do in after trigger. Any operations inside triggers should be fast, pretty fast. Dropping or creating temporary table is not fast operation.
If you have a older PostgreSQL release, you have not to drop temp table every. You should to delete content only. See a article http://postgres.cz/wiki/Automatic_execution_plan_caching_in_PL/pgSQL
The temporary table should be visible as #Pavel explains, but that's not the main issue here.
Your approach might make sense in Oracle with a global temporary table. But the posted Postgres code does not.
The trigger is fired for each row. You would (drop and) create a temp table for every row, and call another trigger, just to do what you could easily do in one trigger directly.
Instead, to keep the old row and set it to archived, plus INSERT a copy of the NEW row:
Demo table:
CREATE TEMP TABLE test (id int, txt text, archived bool DEFAULT FALSE);
Trigger func:
CREATE OR REPLACE FUNCTION trg_test_beforeupdate()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO test SELECT (NEW).*; -- insert a copy of the NEW row
SELECT (OLD).* INTO NEW; -- revert row to previous state
NEW.archived = TRUE; -- just set it to "archived"
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Trigger:
CREATE TRIGGER beforeupdate
BEFORE UPDATE ON test
FOR EACH ROW EXECUTE PROCEDURE trg_test_beforeupdate();
Test:
INSERT INTO test VALUES (1, 'foo'), (2, 'bar');
UPDATE test SET txt = 'baz' WHERE id = 1;
SELECT * FROM test;
Works.

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.

How to add a column to an existing table then use it in a single PostgreSQL function

I have a table being created in a PostgreSQL ( version 9 ) database by a third party product and I need to change that table to add a new column then set the column in question to a standard value.
I have the following in my function:
CREATE FUNCTION alterscorecolumns()
RETURNS void AS
$BODY$
ALTER TABLE "hi_scores" ADD "total_score" integer;
UPDATE "hi_scores" SET total_score = score1+score2+score3;
$BODY$
However, I'm not allowed to do this because it doesn't know that the total_score field exists. I just get the message ERROR: column "total_score" of relation "hi_scores" does not exist.
I am guessing there is some execution-plan related reason for this and that maybe I need to tell it to run the ALTER TABLE before it tries to perform the update, but I can't seem to figure out what I need to do.
You can't do it that way. The SQL in the function is parsed when you create the function. At the time of the creation of the function the column is not there, so you get the error message.
You will need to use dynamic SQL to run the UPDATE statement.
Something like:
CREATE FUNCTION alterscorecolumns()
RETURNS void AS
$BODY$
begin
execute 'ALTER TABLE hi_scores ADD total_score integer';
execute 'UPDATE hi_scores SET total_score = score1+score2+score3';
$BODY$
language plpgsql;
(Not tested, so there might be syntax errors in there)
Just add DEFAULT to your statement like this:
ALTER TABLE "hi_scores" ADD "total_score" integer DEFAULT 0;
#mu already provided: if you want to save this procedure as a function, you have to use dynamic SQL with EXECUTE. But only for the UPDATE. The ALTER TABLE statement works just fine.
As this is obviously a one-time operation (can't add the same column twice), it hardly makes sense to persist a function for the purpose. You could use a DO statement instead:
DO
$BODY$
BEGIN
ALTER TABLE hi_scores ADD total_score integer;
EXECUTE 'UPDATE hi_scores SET total_score = score1+score2+score3';
END;
$BODY$;
But then again, keep it simple: just execute two SQL statements. As soon as the ALTER TABLE is done, the UPDATE will just work normally. Inside a transaction or not - doesn't matter, as long you execute them in order.
ALTER TABLE hi_scores ADD total_score integer;
UPDATE hi_scores SET total_score = score1+score2+score3;

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.