我有一个表 Content
是这样的:
id | text | date | idUser → User | contentType
还有另一个表答案
:
idAnswer → Content | idQuestion → Content | isAccepted
我想确保Answer
的日期大于Question
的日期。问题是 Content
,contentType
= 'QUESTION'。
我尝试使用以下触发器解决此问题,但是当我尝试插入 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;$$;
所以,我的问题是:我真的需要为此创建触发器吗?我看到我不能在 Answer
中使用 CHECK
,因为我需要与另一个表的属性进行比较。有没有其他(更简单/更好)的方法来做到这一点?如果不是,为什么会出现错误,我该如何解决?
最佳答案
您的基本方法是合理的。触发器是一个有效的解决方案。除了 3 个问题 外,它应该可以工作:
1) 您的命名约定:
我们需要查看您的确切表定义才能确定,但证据就在那里。错误消息显示:没有字段
"idanswer"
- 小写。不说 "idAnswer"
- CaMeL 大小写。如果您在 Postgres 中创建 CaMeL 大小写标识符,您将不得不在它们的余生中到处用双引号将它们引用。
2) 中止违反插入
要么引发一个
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.<b>"</b>idAnswer<b>"</b>)
< (SELECT c.date FROM "Content" c WHERE c.id = NEW.<b>"</b>idQuestion<b>"</b>) THEN
RAISE <b>EXCEPTION</b> 'This Answer is an invalid date';
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
正确的解决方案是使用legal, lower case names完全避免此类问题。这包括您不幸的表名以及列名 date
,这是一个 reserved word在标准 SQL 中,不应用作标识符 - 即使 Postgres 允许。
3) 应该是 BEFORE
trigger
CREATE TRIGGER insbef_check
<b>BEFORE</b> INSERT ON "Answer"
FOR EACH ROW EXECUTE PROCEDURE trg_answer_insbef_check();
您想在执行任何其他操作之前中止无效插入。
当然,您必须确保时间戳表 Content
无法更改,或者您需要更多触发器来确保满足您的条件。
Answer
中的 fk 列也是如此。
关于sql - 如果满足条件则阻止插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22733254/