PostgreSQL 两个-table 约束无法正常工作
PostgreSQL two-table constaint not working properly
我运行下面的代码:
-- Table describing messages
CREATE TABLE messages
(
id serial PRIMARY KEY NOT NULL,
text TEXT -- Message can have or not have text
);
-- Table describing media attached to messages
CREATE TABLE messages_attachments
(
message_id integer NOT NULL REFERENCES messages,
-- Messages can have any number of attachments, including 0
attachment_id TEXT NOT NULL
);
-- Messages must have either text or at least one attachment
CREATE FUNCTION message_has_text_or_attachments(integer) RETURNS bool STABLE
AS
$$
SELECT
EXISTS(SELECT 1 FROM messages_attachments WHERE message_id = )
OR
(SELECT text IS NOT NULL FROM messages WHERE id = );
$$ LANGUAGE SQL;
ALTER TABLE messages ADD CONSTRAINT nonempty_message CHECK ( message_has_text_or_attachments(id) );
-- Insert a message with no text and no attachments. Should fail, but it does not
INSERT INTO messages(text) VALUES (NULL);
SELECT *, message_has_text_or_attachments(id) FROM messages;
我预计它会在 INSERT
行失败,因为插入的行违反了检查约束(我们正在插入一条文本为 NULL
的消息,并且该消息没有附件) , 但它 运行s 成功并且下一个查询 returns (1
, NULL
, false
)(这里是一个稍微修改过的 example函数定义(由于数据库版本的原因,使用撇号而不是美元符号)。
一件更有趣的事情是,如果我在添加 CONSTRAINT
之前更改命令的顺序和 INSERT
行,那么 PostgreSQL 将无法 ALTER
table, 因为“check constraint "nonempty_message" is violated by some row
”.
为什么 PostgreSQL 允许插入违反约束的行?我在函数定义的某处弄错了吗?对于如何应用约束以及它们可以依赖哪些 table 是否有一些限制?是 PostgreSQL 错误吗?
来自the docs:
PostgreSQL does not support CHECK constraints that reference table data other than the new or updated row being checked. While a CHECK constraint that violates this rule may appear to work in simple tests, it cannot guarantee that the database will not reach a state in which the constraint condition is false (due to subsequent changes of the other row(s) involved).
我运行下面的代码:
-- Table describing messages
CREATE TABLE messages
(
id serial PRIMARY KEY NOT NULL,
text TEXT -- Message can have or not have text
);
-- Table describing media attached to messages
CREATE TABLE messages_attachments
(
message_id integer NOT NULL REFERENCES messages,
-- Messages can have any number of attachments, including 0
attachment_id TEXT NOT NULL
);
-- Messages must have either text or at least one attachment
CREATE FUNCTION message_has_text_or_attachments(integer) RETURNS bool STABLE
AS
$$
SELECT
EXISTS(SELECT 1 FROM messages_attachments WHERE message_id = )
OR
(SELECT text IS NOT NULL FROM messages WHERE id = );
$$ LANGUAGE SQL;
ALTER TABLE messages ADD CONSTRAINT nonempty_message CHECK ( message_has_text_or_attachments(id) );
-- Insert a message with no text and no attachments. Should fail, but it does not
INSERT INTO messages(text) VALUES (NULL);
SELECT *, message_has_text_or_attachments(id) FROM messages;
我预计它会在 INSERT
行失败,因为插入的行违反了检查约束(我们正在插入一条文本为 NULL
的消息,并且该消息没有附件) , 但它 运行s 成功并且下一个查询 returns (1
, NULL
, false
)(这里是一个稍微修改过的 example函数定义(由于数据库版本的原因,使用撇号而不是美元符号)。
一件更有趣的事情是,如果我在添加 CONSTRAINT
之前更改命令的顺序和 INSERT
行,那么 PostgreSQL 将无法 ALTER
table, 因为“check constraint "nonempty_message" is violated by some row
”.
为什么 PostgreSQL 允许插入违反约束的行?我在函数定义的某处弄错了吗?对于如何应用约束以及它们可以依赖哪些 table 是否有一些限制?是 PostgreSQL 错误吗?
来自the docs:
PostgreSQL does not support CHECK constraints that reference table data other than the new or updated row being checked. While a CHECK constraint that violates this rule may appear to work in simple tests, it cannot guarantee that the database will not reach a state in which the constraint condition is false (due to subsequent changes of the other row(s) involved).