(PostgreSQL)“高级”检查约束问题

发布于 2024-10-20 12:56:05 字数 809 浏览 1 评论 0原文

我使用 PostgreSQL,但正在寻找尽可能标准的 SQL 答案。

我有下表“docs”——

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 version    | integer                | not null default 1
 link_id    | character varying(32)  | 
 content    | character varying(128) | 
Indexes:
    "docs_pkey" PRIMARY KEY, btree (id, version)

id和link_id用于彼此之间具有链接关系的文档,因此link_id自引用id。

问题出在版本上。现在 id 不再是主键(也不会是唯一的)并且不能被 link_id 作为外键引用 -

my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ; 
ERROR:  there is no unique constraint matching given keys for referenced table "docs"

我尝试搜索诸如“如果存在”之类的检查约束,但没有找到任何内容。

任何提示将不胜感激。

I use PostgreSQL but am looking for SQL answer as standard as possible.

I have the following table "docs" --

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 version    | integer                | not null default 1
 link_id    | character varying(32)  | 
 content    | character varying(128) | 
Indexes:
    "docs_pkey" PRIMARY KEY, btree (id, version)

id and link_id are for documents that have linkage relationship between each other, so link_id self references id.

The problem comes with version. Now id is no longer the primary key (won't be unique either) and can't be referenced by by link_id as foreign key --

my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ; 
ERROR:  there is no unique constraint matching given keys for referenced table "docs"

I tried to search for check constraint on something like "if exists" but didn't find anything.

Any tip will be much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我通常这样做:

table document (id, common, columns, current_revision)
table revision (id, doc_id, content, version)

这意味着该文档与其修订版具有一对多关系,并且与当前修订版具有一对一关系。

这样,您始终可以通过简单的联接为当前修订选择完整的文档,并且文档表中只有一个唯一的行,您可以在其中链接父/子关系,但仍然具有版本控制。

I usually do like this:

table document (id, common, columns, current_revision)
table revision (id, doc_id, content, version)

which means that document has a one-to-many relation with it's revisions, AND a one-to-one to the current revision.

That way, you can always select a complete document for the current revision with a simple join, and you will only have one unique row in your documents table which you can link parent/child relations in, but still have versioning.

锦上情书 2024-10-27 12:56:05

尽可能贴近您的模型,您可以将表分成两部分,一个每个“文档”有 1 行,另一个每个“版本”有 1 行:

您有下表“版本”——

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 version    | integer                | not null default 1
 content    | character varying(128) | 
Indexes:
    "versions_pkey" PRIMARY KEY, btree (id, version)

以及下表“docs”——

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 link_id    | character varying(32)  | 
Indexes:
    "docs_pkey" PRIMARY KEY, btree (id)

现在

my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ; 

是允许的,并且您也想要:

my_db=# ALTER TABLE versions ADD FOREIGN KEY(id) REFERENCES docs; 

当然没有什么可以阻止您获得类似于原始表的“组合”视图:

CREATE VIEW v_docs AS
SELECT id, version, link_id, content from docs join versions using(id);

Sticking as close to your model as possible, you can split your table into two, one which has 1 row per 'doc' and one with 1 row per 'version':

You have the following table "versions" --

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 version    | integer                | not null default 1
 content    | character varying(128) | 
Indexes:
    "versions_pkey" PRIMARY KEY, btree (id, version)

And the following table "docs" --

    Column  |          Type          | Modifiers              
------------+------------------------+--------------------
 id         | character varying(32)  | not null
 link_id    | character varying(32)  | 
Indexes:
    "docs_pkey" PRIMARY KEY, btree (id)

now

my_db=# ALTER TABLE docs ADD FOREIGN KEY(link_id) REFERENCES docs (id) ; 

is allowed, and you also want:

my_db=# ALTER TABLE versions ADD FOREIGN KEY(id) REFERENCES docs; 

of course there is nothing stoping you getting a 'combined' view similar to your original table:

CREATE VIEW v_docs AS
SELECT id, version, link_id, content from docs join versions using(id);
ㄖ落Θ余辉 2024-10-27 12:56:05

根据您是否需要,您可以简单地创建一个包含版本字段的外键。这是指向唯一行的唯一方法...

如果这不起作用,您可以编写一个触发器(针对表上的所有更新和插入)来进行检查。请注意,您还需要 docs 表上的触发器,以限制对该表进行会破坏键的修改(例如对键值本身的 DELETE 或 UPDATE)。

您不能使用 CHECK 约束来执行此操作,因为 CHECK 约束无法访问另一个表中的数据。

Depending on if it's what you want, you can simply create a FOREIGN KEY that includes the version field. That's the only way to point to a unique row...

If that doesn't work, you can write a TRIGGER (for all UPDATEs and INSERTs on the table) that makes the check. Note that you will also need a trigger on the docs table, that restricts modifications on that table that would break the key (such as a DELETE or UPDATE on the key value itself).

You cannot do this with a CHECK constraint, because a CHECK constraint cannot access data in another table.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文