need help writing this compound trigger - sql

i have a column in my table that i need to update on insert or update, i can't do it with a simple trigger because the new value has to be SELECTED from the same table and other tables (which would generate trigger is mutating error).
my solution was to use a compound trigger, after a little bit of documentation i wrote this code:
CREATE OR REPLACE TRIGGER update_contract_n FOR
INSERT OR UPDATE ON contract
COMPOUND TRIGGER
v_n VARCHAR(70);
AFTER EACH ROW IS BEGIN
v_n := object_contract(:new.id_contract);
END AFTER EACH ROW;
AFTER STATEMENT IS BEGIN
UPDATE contract
SET
n = v_n
WHERE
id_contract = :new.id_contract;
END AFTER STATEMENT;
END update_contract_n;
the function object_contract() joins 4 tables one of which is the table contract and returns a varchar.
when i compile the trigger code i get this error :
pls-00679 trigger binds not allowed in before/after statement section
but i don't know what i'm doing wrong since the variable binding was done in AFTER EACH ROW section not in AFTER STATEMENT.
any help would be appreciated (fixing or rewriting the code), a simple guide on how to use a compound trigger would also be appreciated.
EDIT:
i found the problem, i was referencing :new.id_contract in AFTER STATEMENT and i fixed it, but now i am getting table is mutating trigger/function may not see it
how can i fix that?

Related

Postgres: Update table sorting on new record inserted or removed

I'm trying to sort table automatically by specified row each time a new record is added (or removed or updated).
For that, I've create a function
CREATE FUNCTION pid_cluster_function()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
-- trigger logic
cluster verbose public.pid using pid_idx;
END;
$$
and add a trigger
CREATE trigger pid_cluster_trigger
after INSERT or update or DELETE on public.pid
FOR EACH row
execute procedure pid_cluster_function();
but with adding a record
INSERT INTO public.pid (pid,pid_name) VALUES ('111','new 111');
I've received such an error
SQL Error [55006]: ERROR: cannot CLUSTER "pid" because it is being used by active queries in this session
Where: SQL statement "cluster verbose public.pid using pid_idx"
PL/pgSQL function pid_cluster_function() line 5 at SQL statement
What is the reason for this error?
Or is it possible to achieve sorting by adding or modifying the records in some other way?
Ok, thank you, everyone, in the comments. I see that my idea is not clever =)

Encountered the symbol "end-of-file" when expecting one of the following in simple trigger

create or replace TRIGGER PR_POZ_ZAM_CENA_TRG AFTER UPDATE ON PR_POZYCJA_ZAMOWIENIA
FOR EACH ROW BEGIN
BEGIN
UPDATE PR_POZYCJA_ZAMOWIENIA
SET PR_POZYCJA_ZAMOWIENIA.cena_za_sztuke = 1.1*PR_PRODUKT.cena
WHERE PR_PRODUKT.id_produktu=:new.id_produktu;
END PR_POZYCJA_ZAMOWIENIA;
heres my code, i have no idea why its wrong, I think I miss : somewhere or the query is bad, but idk how to fix it, tried using : and changing PR_POZYCJA_ZAMOWIENIA.cena_za_sztuke to new.cena_za_sztuke but it didnt work
You have BEGIN twice, and you only END once. The final END needs to atch the name of the trigger, not the table. (Giving the name is optional, but useful.)
You are also updating the same trigger the update is against; which will cause the trigger to fire again; which will cause a further update; which will fire the trigger again...
You can assign a column value in the row being updated, in this case with a select ... into:
create or replace TRIGGER PR_POZ_ZAM_CENA_TRG
AFTER UPDATE ON PR_POZYCJA_ZAMOWIENIA
FOR EACH ROW
BEGIN
SELECT 1.1*PR_PRODUKT.cena
IMTO :new.cena_za_sztuke
FROM PR_PRODUKT
WHERE PR_PRODUKT.id_produktu=:new.id_produktu;
END PR_POZ_ZAM_CENA_TRG:
/
If that calculation is constant, it might be simpler to calculate it when querying the table, or via a view, rather than storing and maintaining that derived value.

A Trigger which will implement update cascade to PK

I need to write a trigger which will implement update cascade for (gameno) code for SummerGames but I keep encountering `Error(11,1): PLS-00103: Encountered the symbol "CREATE
I'm using Oracle SQL Developer.
My current code:
create or replace TRIGGER SG_GAMENO_UPDATE
BEFORE UPDATE OF SG_GAMENO ON SUMMERGAMES
FOR EACH ROW
BEGIN
UPDATE SUMMERGAMES
SET SG_GAMENO = :new.SG_GAMENO
WHERE SG_GAMENO = :old.SG_GAMENO;
END;
You need to end the trigger statement, which is partly PL/SQL, with a / on a line on its own. That will end the statement and cause it to be run.
create or replace TRIGGER SG_GAMENO_UPDATE
BEFORE UPDATE OF SG_GAMENO ON SUMMERGAMES
FOR EACH ROW
BEGIN
UPDATE SUMMERGAMES
SET SG_GAMENO = :new.SG_GAMENO
WHERE SG_GAMENO = :old.SG_GAMENO;
END;
/
At the moment whatever is folowing this in your script - which seems to be another create statement - is being seen as part of the same trigger creation, and that keyword isn't valid within a block.
Your trigger doesn't seem to make any sense, and at best will lead to infinite recursion when you attempt an update (which will be detected and killed), but that's a separate issue. Perhaps you meant to update a child table, rather than the same table the trigger is against. But you shouldn't really be updating a PK at all; that's why synthetic keys are generally preferred over natural ones. gameno sounds synthetic anyway.
it will something about the separation of your codes, i mean when you executed the code snippet above, you marked off some part from another code, that's why you get syntactic error. try to execute just the code above, delete anyting else from the sql editor

Solving the mutating table problem in Oracle SQL produces a deadlock

Hey, I'm trying to create a trigger in my Oracle database that changes all other records except the one that has just been changed and launched the trigger to 0. Because I am updating records in the same table as the one that launched the trigger I got the mutating table error. To solve this, I put the code as an anonymous transaction, however this causes a deadlock.
Trigger code:
CREATE OR REPLACE TRIGGER check_thumbnail AFTER INSERT OR UPDATE OF thumbnail ON photograph
FOR EACH ROW
BEGIN
IF :new.thumbnail = 1 THEN
check_thumbnail_set_others(:new.url);
END IF;
END;
Procedure code:
CREATE OR REPLACE PROCEDURE check_thumbnail_set_others(p_url IN VARCHAR2)
IS PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE photograph SET thumbnail = 0 WHERE url <> p_url;
COMMIT;
END;
I assume I'm causing a deadlock because the trigger is launching itself within itself. Any ideas?
Using an autonomous transaction for this sort of thing is almost certainly a mistake. What happens if the transaction that inserted the new thumbnail needs to rollback? You've already committed the change to the other rows in the table.
If you want the data to be transactionally consistent, you would need multiple triggers and some way of storing state. The simplest option would be to create a package with a collection of thumbnail.url%type then create three triggers on the table. A before statement trigger would clear out the collection. A row-level trigger would insert the :new.url value into the collection. An after statement trigger would then read the values from the collection and call the check_thumbnail_set_others procedure (which would not be an autonomous transaction).

ORA-04098: Simple trigger is invalid. Why?

There is something wrong with this trigger. But what?
CREATE TRIGGER MYCOOLTRIGGER
AFTER INSERT ON MYCOOLTABLE
REFERENCING NEW AS newRow
FOR EACH ROW
DECLARE
BEGIN
END MYCOOLTRIGGER;
SQL Developer output:
Warning: execution completed with warning
TRIGGER MYCOOLTRIGGER Compiled.
Is there any way to get more info on this Warning?
P.S.
This question could use a better title. ;)
Oracle requires that you have something between BEGIN and END.
You can use NULL (a no-op):
CREATE OR REPLACE TRIGGER MYCOOLTRIGGER
AFTER INSERT ON MYCOOLTABLE
REFERENCING NEW AS newRow
FOR EACH ROW
DECLARE
BEGIN
NULL;
END MYCOOLTRIGGER;
If you want to see what the errors are:
show errors trigger mycooltrigger;