Rei*_*ica 5 postgresql database-design referential-integrity constraints foreign-keys
我在 Postgres 9.3 数据库中有以下场景:
我想确保对于引用表 B 的表 C 的每一行,cba = ca 也就是说,如果 C 引用了 B,那么两行都应该指向表 A 中的同一行。
在这种情况下,是否有更好的方法来强制执行数据完整性?
有一个非常简单、万无一失的解决方案。适用于 Postgres 9.3 - 当提出原始问题时。适用于当前的 Postgres 13 - 当添加赏金中的问题时:
\n\n\n希望了解是否可以在没有数据库触发器的情况下实现这一点
\n
FOREIGN KEY约束可以跨越多个列。只需将表 A 的 ID 包含在从表 C 到表 B 的 FK 约束中即可。这会强制 B 和 C 中的链接行始终指向 A 中的同一行。例如:
CREATE TABLE a (\n a_id int PRIMARY KEY\n);\n\nCREATE TABLE b (\n b_id int PRIMARY KEY\n, a_id int NOT NULL REFERENCES a\n, UNIQUE (a_id, b_id) -- redundant, but required for FK\n);\n\nCREATE TABLE c (\n c_id int PRIMARY KEY\n, a_id int NOT NULL REFERENCES a\n, b_id int\n, CONSTRAINT fk_simple_and_safe_solution\n FOREIGN KEY (a_id, b_id) REFERENCES b(a_id, b_id) -- THIS !\n);\nRun Code Online (Sandbox Code Playgroud)\n最小样本数据:
\nINSERT INTO a(a_id) VALUES\n (1)\n, (2);\n\nINSERT INTO b(b_id, a_id) VALUES\n (1, 1)\n, (2, 2);\n\nINSERT INTO c(c_id, a_id, b_id) VALUES\n (1, 1, NULL) -- allowed\n, (2, 2, 2); -- allowed\nRun Code Online (Sandbox Code Playgroud)\n按要求不允许:
\nINSERT INTO c(c_id, a_id, b_id) VALUES (3,2,1);\nRun Code Online (Sandbox Code Playgroud)\n\n\nRun Code Online (Sandbox Code Playgroud)\nERROR: insert or update on table "c" violates foreign key constraint "fk_simple_and_safe_solution"\nDETAIL: Key (a_id, b_id)=(2, 1) is not present in table "b".\n
db<>在这里摆弄
\nFK 约束的默认MATCH SIMPLE行为是这样的(引用手册):
\n\n\n
MATCH SIMPLE允许任何外键列为空;如果其中任何一个为空,则该行不需要在引用的表中具有匹配项。
c(b_id)因此仍然允许NULL 值(根据要求: “可选字段”)。对于这种特殊情况,FK 约束被“禁用”。
我们需要逻辑冗余UNIQUE约束b(a_id, b_id)以允许 FK 引用它。但是,通过将其设置为 on(a_id, b_id)而不是(b_id, a_id),它本身也很有用,可以提供有用的索引 onb(a_id)来支持其他 FK 约束等。看:
(相应地,附加索引c(a_id)通常很有用。)
进一步阅读:
\n\n| 归档时间: |
|
| 查看次数: |
353 次 |
| 最近记录: |