我有一个表这样的内容:
id | text | date | idUser → User | contentType
另一张表答案:
idAnswer → Content | idQuestion → Content | isAccepted
我想确保答案的日期大于问题的日期.问题是ContentType =’QUESTION’的内容.
我尝试使用以下触发器解决此问题,但是当我尝试插入Answer时出现错误:
06002
触发:
CREATE TRIGGER check_valid_answer AFTER INSERT ON "Answer" FOR EACH ROW EXECUTE PROCEDURE check_valid_date_answer();
触发功能:
CREATE FUNCTION check_valid_date_answer() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN IF (SELECT "Content".date FROM "Content" WHERE "Content".id = NEW.idAnswer) < (SELECT "Content".date FROM "Content" WHERE "Content".id = NEW.idQuestion) THEN RAISE NOTICE 'This Answer is an invalid date'; END IF; RETURN NEW; END;$$;
所以,我的问题是:我真的需要为此创建触发器吗?我看到我无法使用CHECK in Answer,因为我需要与另一个表的属性进行比较.还有其他(更简单/更好)的方法吗?如果没有,为什么错误,我该如何解决?
解决方法
你的基本方法是合理的.触发器是有效的解决方案.它应该工作除了3个问题:
1)您的命名约定:
我们需要确定您的确切表定义,但证据就在那里.错误消息说:没有字段“idanswer” – 小写.不说“idAnswer” – CaMeL案.如果您在Postgres中创建CaMeL案例标识符,则必须在您的余生中将它们双重引用.
2)中止违反插入
>提出EXCEPTION而不是友好通知实际中止整个交易.
>或RETURN NULL而不是RETURN NEW,只是静默地中止插入的行,而不会引发异常并且不返回任何内容.
CREATE FUNCTION trg_answer_insbef_check() RETURNS trigger AS $func$ BEGIN IF (SELECT c.date FROM "Content" c WHERE c.id = NEW."idAnswer") < (SELECT c.date FROM "Content" c WHERE c.id = NEW."idQuestion") THEN RAISE EXCEPTION 'This Answer is an invalid date'; END IF; RETURN NEW; END $func$ LANGUAGE plpgsql;
正确的解决方案是专门使用legal,lower case names并完全避免这些问题.这包括你不幸的表名以及列名日期,它是标准sql中的reserved word,不应该用作标识符 – 即使Postgres允许它.
3)应该是BEFORE
trigger
CREATE TRIGGER insbef_check BEFORE INSERT ON "Answer" FOR EACH ROW EXECUTE PROCEDURE trg_answer_insbef_check();
您希望在执行任何其他操作之前中止无效插入.
当然,您必须确保时间戳表内容无法更改,或者您需要更多触发器以确保满足您的条件.答案中的fk列也是如此.