Hug*_*usa 7 sql postgresql triggers database-design constraints
我有这样一张桌子Content:
id | text | date | idUser ? User | contentType
Run Code Online (Sandbox Code Playgroud)
另一张桌子Answer:
idAnswer ? Content | idQuestion ? Content | isAccepted
Run Code Online (Sandbox Code Playgroud)
我想确保Answer日期大于Question日期.一个问题是一个Content带有contentType="问题".
我尝试使用以下触发器解决此问题,但是当我尝试插入时Answer出现错误:
Run Code Online (Sandbox Code Playgroud)ERROR: record "new" has no field "idanswer" CONTEXT: SQL statement "SELECT (SELECT "Content".date FROM "Content" WHERE "Content".id = NEW.idAnswer) < (SELECT "Content".date FROM "Content" WHERE "Content".id = NEW.idQuestion)" PL/pgSQL function "check_valid_date_answer" line 2 at IF
触发:
CREATE TRIGGER check_valid_answer
AFTER INSERT ON "Answer"
FOR EACH ROW EXECUTE PROCEDURE check_valid_date_answer();
Run Code Online (Sandbox Code Playgroud)
触发功能:
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;$$;
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:我真的需要为此创建触发器吗?我看到我不能使用CHECKin,Answer因为我需要与另一个表的属性进行比较.还有其他(更简单/更好)的方法吗?如果没有,为什么错误,我该如何解决?
你的基本方法是合理的.触发器是有效的解决方案.它应该工作除了3个问题:
我们需要确定您的确切表定义,但证据就在那里.错误消息说:has no field "idanswer"- 小写.不说"idAnswer"- CaMeL案.如果您在Postgres中创建CaMeL案例标识符,则必须在您的余生中将它们双重引用.
提出一个EXCEPTION而不是一个友好NOTICE的实际上中止整个交易.
或者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;Run Code Online (Sandbox Code Playgroud)
在妥善解决是使用合法的,小写的名字完全和完全避免这些问题.这包括你不幸的表名和列名date,它是标准SQL中的保留字,不应该用作标识符 - 即使Postgres允许它.
BEFORE触发器CREATE TRIGGER insbef_check
BEFORE INSERT ON "Answer"
FOR EACH ROW EXECUTE PROCEDURE trg_answer_insbef_check();Run Code Online (Sandbox Code Playgroud)
您希望在执行任何其他操作之前中止无效插入.
当然,您必须确保Content无法更改时间戳表,或者需要更多触发器以确保满足您的条件.
对于fk列来说也是如此Answer.