PostgreSQL 中的触发器

发布于 2024-10-15 10:22:05 字数 796 浏览 1 评论 0原文

我有表“Candidates”,其中包含id(主键)和application_counter
和带有外键 (candidate_id) 的表“Applications”。我希望每次添加或删除应用程序时都修改 application_counter(或通过更改 candidate_id 进行修改)。

我所能做的就是写:

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

问题是我怎样才能写这个触发器?

页面摘要 http://www.postgresql.org/docs/8.1/交互式/sql-createtrigger.html

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

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 )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

玩物 2024-10-22 10:22:05

我将使用一个视图,INNER JOIN 两个表,并计算 applications 表中的行数。 (请参阅COUNT()。)可以禁用触发器;这种观点总会给你正确的答案。

(稍后......)

我理解您希望将“申请”表中候选人的行数限制为 3 或更少。在这种情况下,我认为最好对“应用程序”使用 CHECK() 约束,而不是结合使用“应用程序”上的触发器和 CHECK() 约束关于“候选人”。

要在 PostgreSQL 中执行此操作,您必须使用一个函数,并从 CHECK() 调用该函数。 (据我所知。您仍然无法在 CHECK() 约束中执行任意 SELECT 语句,对吧?)因此,您需要创建这个函数,

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;

然后您需要向表“applications”添加 CHECK() 约束。

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

“< 3”,因为在添加行之前评估 CHECK() 约束。也许值得测试一下,看看它在延迟约束下的表现如何。如果以后有时间,我会这样做。

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.

羞稚 2024-10-22 10:22:05
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;

我希望您能明白...现在也适用于更新的候选人 ID。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文