我正在尝试在Postgres中设计一个tree模式(不是adjacency list,不是directed acyclic graph)。从到目前为止我尝试过的模式中,我很难得出我假设正确的行为。我对自己的假设和架构都持开放态度!
我从简单的事情开始,应该强制parent_id实际上存在。
CREATE TABLE node (
id SERIAL PRIMARY KEY,
parent_id INT REFERENCES node (id) ON DELETE CASCADE
);
我喜欢这样,我可以为根节点插入NULL作为parent_id(这使得 some 递归查询稍后变得更容易)。
INSERT INTO node (parent_id) VALUES (null),(1),(1),(2);
id parent_id
-- ---------
1 [null]
2 1
3 1
4 2
但是,我还可以创建 unlimited NULL parent_id引用,这绝对是 所不希望的。
INSERT INTO node (parent_id) VALUES (null),(null),(null);
id parent_id
-- ---------
1 [null]
2 [null]
3 [null]
我还可以拥有根节点引用本身(有用)吗?
INSERT INTO node (parent_id) VALUES (1),(1),(1),(2);
id parent_id
-- ---------
1 1
2 1
3 1
4 2
哦,但这意味着我可以猜在 any INSERT上的下一个序列,是吗?这似乎并不理想。
INSERT INTO node (parent_id) VALUES (1),(2),(3)
id parent_id
-- ---------
1 1
2 2
3 3
所以,也许我需要调查一下参考?该文档似乎建议MATCH FULL或NOT NULL约束。
使用给定的匹配类型,将插入到引用列中的值与引用表和引用列的值进行匹配。共有三种匹配类型:“完全匹配”,“部分匹配”和“简单匹配”(默认设置)。除非所有外键列为空,否则MATCH FULL将不允许多列外键的一列为空;如果它们全为空,则不需要该行在引用表中具有匹配项。 MATCH SIMPLE允许任何外键列为空;如果它们中的任何一个为null,则不需要该行在引用表中具有匹配项。 MATCH PARTIAL尚未实现。 (当然,可以将NOT NULL约束应用于引用列,以防止出现这些情况。)
https://www.postgresql.org/docs/9.6/sql-createtable.html
让我们尝试NOT NULL。
CREATE TABLE node (
id SERIAL PRIMARY KEY,
parent_id INT NOT NULL REFERENCES node (id) ON DELETE CASCADE
);
但是,现在我不能使用NULL或自引用创建根节点了……产生了什么?!