0

I'm trying to create a before update trigger for a table. Basically, on each row update I need to set additional column on the same row on the same table.

However, for some reason, each trigger call results in setting values from a previous trigger call.

Here's the code for my trigger:

create or replace function test_trigger_func() returns trigger as $$
    declare
        v_department  text;
    begin
        select department.name into v_department
        from salesprofile
        left join (
           select department.name from salesprofile join department on department.id = (
               salesprofile.solutionscreteria #>> '{departments, 0}'
           )::int4 where salesprofile.id = NEW.id
        ) department on true
        where salesprofile.id = NEW.id
        group by department.name;
        
        NEW.department = v_department;
        
        raise notice 'DEP: %', v_department;
        raise notice 'NEW DEP: %', NEW.department;
        
        return NEW;
    end;
$$ language plpgsql;

drop trigger if exists test_trigger on salesprofile;

create trigger test_trigger before update on salesprofile
for each row execute procedure test_trigger_func();

The select statement inside the test_trigger_func function works correctly when run outside the function. But the raise notice statements show incorrect (previous) values when the select is called from inside the test_trigger_func function.

The salesprofile.solutionscreteria #>> '{departments, 0}' statement contains the id for the row in the department table. And I'm trying to set the department column on the salesprofile table row from the "department".name on each salesprofile row update (by modifying NEW.department = ...).


The behaviour I get:

  • the select statement is perfectly fine and works as expected (when called as is, outside the function).

  • when I make the very first update to the salesprofile row, the trigger sets the department column as NULL (the column does not get updated at all);

  • when I make the second update to the salesprofile row, the trigger sets the department column as the value that I was trying to set on the first update;

  • when I make the third update to the salesprofile row, the trigger sets the department column as the value that I was trying to set on the second update;

  • and so on...

  • if I put the incorrect value to the salesprofile.solutionscreteria #>> '{departments, 0}' value, the first trigger update will not cause any errors.

  • and then if I set the correct value after that, the trigger will fire with an error (caused by the previous trigger call with incorrect value).


I don't get how and why this is happening and I do hope I'm explaining the behaviour in an intelligible way.

Is this the expected behaviour for potgresql triggers? If not, then could you explain what's happening and how to make it work correctly?

Denis Yakovenko
  • 3,241
  • 6
  • 48
  • 82
  • 1
    It is a `BEFORE` trigger so it occurs before the `salesprofile` table has the `NEW` data. I'm not entirely following but I'm go to say that this `salesprofile.solutionscreteria #>> '{departments, 0}'` is using the existing(previous) row not the update data the trigger is running on. Have you tried `NEW.solutionscreteria`? – Adrian Klaver Aug 17 '21 at 14:22
  • @AdrianKlaver This actually did the trick. You can post this as an answer and I will mark it as accepted. Thank you! – Denis Yakovenko Aug 17 '21 at 15:13

1 Answers1

1

It is a BEFORE trigger so it occurs before the salesprofile table has the NEW data. I'm not entirely following but I'm go to say that this salesprofile.solutionscreteria #>> '{departments, 0}' is using the existing(previous) row not the update data the trigger is running on. Try it with NEW.solutionscreteria.

Adrian Klaver
  • 15,886
  • 2
  • 17
  • 28