1

I have table "Candidates" with id (primary key) and application_counter
and table "Applications" with foreign key (candidate_id). I want application_counter to be modified each time Application is added or removed (or modified by changing candidate_id).

All I can do is to write:

CREATE TRIGGER myTrigger AFTER INSERT OR DELETE OR UPDATE
ON "Applications" FOR EACH ROW
EXECUTE PROCEDURE funcname ( arguments )

And the question is How can I write this trigger?

Synopsis from page http://www.postgresql.org/docs/8.1/interactive/sql-createtrigger.html

CREATE TRIGGER name { BEFORE | AFTER } { event [ OR ... ] }
ON table [ FOR [ EACH ] { ROW | STATEMENT } ]
EXECUTE PROCEDURE funcname ( arguments )
1

2 Answers 2

3

I'd use a view, INNER JOIN the two tables, and count the rows in the applications table. (See COUNT().) Triggers can be disabled; that view will always give you the right answer.

(Later . . .)

I understand you want to limit a candidate's rows in the table "applications" to 3 or less. In that case, I think it's best to use a CHECK() constraint on "applications" rather than the combination of a trigger on "applications" and a CHECK() constraint on "candidates".

To do that in PostgreSQL, you have to use a function, and call the function from the CHECK(). (As far as I know. You still can't execute arbitrary SELECT statements in CHECK() constraints, right?) So, you'd create this function,

CREATE FUNCTION num_applications(cand_id integer)
  RETURNS integer AS
$BODY$ 

  DECLARE 
    n integer; 
  BEGIN 
    select count(*) 
    into n 
    from applications
    where (candidate_id = cand_id);

    return n; 
  END; 
$BODY$ 
LANGUAGE plpgsql;

and then you'd add a CHECK() constraint to the table 'applications'.

ALTER TABLE applications
  ADD CONSTRAINT max_of_three CHECK (num_applications(candidate_id) < 3);

"< 3" because the CHECK() constraint is evaluated before adding a row. It's probably worth testing to see how this behaves with deferred constraints. If I have time later, I'll do that.

Sign up to request clarification or add additional context in comments.

6 Comments

+1 a trigger seems to be overkill here (unless it is for training purposes)
I need triger because there is CHECK condition on application_counter that states that each candidate can post max 3 applications.
You could also use a SELECT count() in the trigger... would be fast also if there is a useful index on candidate_id.
What do you mean by 'useful'?
@Miko Kronn: In that case, I'd rather use a CHECK() constraint on the table Applications. I'll edit my answer to show how to do that.
|
3
CREATE TRIGGER myname AFTER INSERT, DELETE OR UPDATE 
ON table applications
EXECUTE PROCEDURE myfunc();

CREATE FUNCTION myfunc() RETURNS TRIGGER AS 
BEGIN
    IF TG_OP != 'DELETE' THEN
        update candicate set application_count = application_count + 1 where id = new.candidate_id;
    END IF;
    IF TG_OP != 'INSERT' THEN
        update candicate set application_count = application_count + 1 where id = old.candidate_id;
    END IF;
END;

I hope you get the idea... works now also with updated candidate_id's.

4 Comments

How can I write this function to do what I want? I mean, how can I get id of "Candidates" being affected. There can be one (INSERT or DELETE) or two (UPDATE).
Inside "myFunc()", for the Insert side, "Update candidates set counter = counter + 1 where id = new.candidate_id". For the delete trigger, refer to "old.candidate.id". Updates don't do anything unless it is possible to change the candidate_id field, in which case you decrement from old and increment new.
This might be a new question but... How can I prevent update on candidate_id column?
Raise an exception in the trigger, if old.candiate_id is distinct from new.candidate_id

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.