Trigger After Update In SQL Compiles But Does Not Seem To Fire - sql

I have a trigger that should update a certain column, Points, after an update is made to a record in that same row. To do this, I have created a series of functions calc_extrapoint and calc_fieldgoalpoint to facilitate the process. Both of these functions work and return the correct values when run manually.
However, when I try to have the trigger fire after an update to the table, which most likely will happen with the columns ExtraPoint or FieldGoal the Points column is not updated as I'd expect.
For example iniitally in my table all values of each record starts as 0, 0, 0 for points, extra point, and field goal columns respectively. When I update the extra point column though to say 2, I expect the Points column to be 2. If I update again this time with field goal points to 2, I expect my Points column to be set to 8.
create or replace function calc_points() returns trigger as $$
begin
NEW."Points" := calc_extrapoint(NEW."ExtraPoint") + calc_fieldgoalpoint(NEW."FieldGoal");
return NEW;
end
$$ LANGUAGE plpgsql;
DROP TRIGGER calc_points on playerdata;
CREATE TRIGGER calc_points AFTER UPDATE ON playerdata
FOR EACH ROW EXECUTE PROCEDURE calc_points();
The trigger and functions all compile appropriately, but are not firing as expected. Is there something I'm missing to complete the action?

Modifying NEW in an AFTER trigger won't do anything. The row has already been written. Put a RAISE NOTICE 'Trigger fired'; in there; you'll get the notice. It's just that the trigger fires, but does nothing.
That's why we have BEFORE triggers. If you want to modify the row to be written to the table, you must use a BEFORE trigger.

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 =)

Invoking procedure from a trigger to validate birthdate

I have created a trigger below (Trig 1)to fire before insert on employee table. Then this trigger will invoke the procedure (Proc 1) which will validate the birthdate being not earlier the the current date. if not proceed with the insert, but if date is earlier than current date, it will show a message like "invalid birthdate".
(Trig 1)
create or replace trigger VALIDATE_BDAY_TRIG
before insert on employee
for each row
declare
birth_date date;
employee_birthdate date;
begin
birth_date := employee_birthdate;
val_bday_proc birth_date;
end VALIDATE_BDAY_TRIG;
(Proc 1)
create or replace procedure val_bday_proc(
date_of_birth in date)
as
begin
if date_of_birth > current_date()
then raise_application_error(-20000, 'Employee birth date should not be earlier than the current date');
end;
When calling a stored procedure, you should pass variables between parentheses:
val_bday_proc(birth_date)
Also, you need to get the actual value that is to be inserted, because now employee_birthdate is just a variable, and will be null. You can use :new.fieldname to get the value of the field 'fieldname' of the new record. No need to declare variables for that at all, so your trigger could look like this, assuming the field is called employee_birthdate:
Create or Replace trigger VALIDATE_BDAY_TRIG
before insert on employee
for each row
begin
val_bday_proc(:new.employee_birthdate);
end VALIDATE_BDAY_TRIG;
The stored procedure seems to be okay, except it's missing the end if; to close the if-statement.
Some side notes:
You seem to be confusing earlier and later. The code in the proc is okay, but in the error message and in your question text you got it the other way around.
You could (maybe should?) also check this on update, otherwise you can insert an earlier date and then update it to some date in the future. You could make a separate trigger for this, or modify the current one to also trigger on update: (before insert or update).
It may help to have a naming convention for triggers that show their context (whether they are insert and/or update, row level or statement level). That helps you find the right one if you have multiple triggers.
It's a good idea to at least consider not putting this in a trigger at all. I learned the hard way that having a lot of business logic in triggers will eventually affect performance, is hard to debug, and hard to change. These kind of checks could be made in an application layer that stores the employee-data.

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.

Oracle Trigger Only Fires After I do a explicit Commit

I am new to triggers and just learning them. When I delete a row from the respective table I do not get a DBMS Output, but I know the row has been deleted. The only time I get a DBMS output for the trigger is when do a COMMIT or a RollBACK. Is this correct? Form what I have read the Trigger should automatically run when I delete a row but that doesn't seem to be the case for me. Additionally I ensured the trigger was enabled and set serveroutput was on.
create or replace Trigger tadr_Employee
After Delete ON employee
For Each Row
Begin
DBMS_OUTPUT.PUT_LINE('Tigger Fired After deleting anything from Lab10_Employees tadr');
End;
Delete FROM Employee
Where EmployeeID = 11111;

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).