我有一张像这样的表Content
:
id | text | date | idUser → User | contentType
另一张表Answer
:
idAnswer → Content | idQuestion → Content | isAccepted
我想确保Answer
的日期大于Question
的日期。问题是Content
contentType
='问题'。
我尝试使用以下触发器解决此问题,但当我尝试插入Answer
时出现错误:
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();
触发功能:
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
中使用Answer
因为我需要与另一个表的属性进行比较。还有其他(更简单/更好)的方法吗?如果没有,为什么错误以及如何解决?
答案 0 :(得分:6)
您的基本方法是合理的。触发器是有效的解决方案。除 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;
正确的解决方案是专门使用legal, lower case names并完全避免此类问题。这包括您不幸的表名以及列名date
,它是标准SQL中的reserved word,不应该用作标识符 - 即使Postgres允许它。
BEFORE
trigger CREATE TRIGGER insbef_check
BEFORE INSERT ON "Answer"
FOR EACH ROW EXECUTE PROCEDURE trg_answer_insbef_check();
您希望在执行任何其他操作之前中止无效插入。
当然,您必须确保时间戳表Content
无法更改,或者您需要更多触发器以确保满足您的条件。
Answer
中的fk列也是如此。
答案 1 :(得分:1)
我会以不同的方式处理这个问题。
建议:
因此编写一个sql函数来检查一个日期早于另一个日期的条件,并添加检查约束。是的,您可以从功能中的其他表中进行选择。
我写了类似的东西(复杂的检查)in answer to this question on SO。