【发布时间】:2017-06-14 07:58:05
【问题描述】:
我正在使用 PostgreSQL 使用邻接列表方法对树数据结构进行建模。我希望能够在每个叶子上存储额外的数据,指示这棵树属于哪个组:
CREATE TABLE groups (
group_id integer PRIMARY KEY
);
CREATE TABLE leafs (
leaf_id integer PRIMARY KEY,
parent_id integer REFERENCES leafs ON DELETE CASCADE ON UPDATE CASCADE,
group_id integer REFERENCES groups ON DELETE CASCADE ON UPDATE CASCADE NOT NULL
);
我还想确保每个叶子只能连接到同一个组。看起来这可以通过创建 TRIGGER 或 CHECK 约束来完成。我有两个问题:
处理这种特殊情况的最有效/正确的方法是什么,
TRIGGER或CHECK约束? (以及在这两者之间进行选择的经验法则是什么)是否有更好的方法来强制此模型的一致性(或者可能有替代方法来对此类树组进行建模)。
谢谢,
TRIGGER 版本代码:
CREATE OR REPLACE FUNCTION after_leaf_update()
RETURNS trigger AS
$$
BEGIN
IF (NEW.parent_id IS NOT NULL) AND (SELECT group_id FROM leafs WHERE leaf_id=NEW.parent_id) <> NEW.group_id THEN
RAISE EXCEPTION 'group_id of node/leaf does not match!!!';
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER leafs_consistency_check
BEFORE INSERT OR UPDATE
ON leafs
FOR EACH ROW
EXECUTE PROCEDURE after_leaf_update();
CHECK 约束版本的代码:
CREATE OR REPLACE FUNCTION leafs_consistency_check_constraint(prn_id integer, grp_id integer) RETURNS BOOL AS
$$
BEGIN
IF (prn_id IS NOT NULL) AND (SELECT group_id FROM leafs WHERE leaf_id=prn_id) <> grp_id THEN
RAISE EXCEPTION 'CHECK: group_id of node/leaf does not match!!!';
END IF;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
ALTER TABLE leafs ADD constraint group_id_constraint check ( leafs_consistency_check_constraint(parent_id, group_id) );
【问题讨论】:
-
你检查PostgreSQL ltree module了吗?是否适用?你能在
F.21.4. Example中做类似CREATE TABLE test (path ltree, YOUR_LABEL_HERE text NOT NULL)的事情吗?使用CREATE EXTENSION ltree为数据库启用模块。 -
你检查过这个SO question的答案了吗?有帮助吗?
-
@flutter - 谢谢你的链接!我不知道 ltree 模块 - 我会检查一下!
-
@flutter 重新使用继承:我已经检查过了 - 对我来说似乎没有帮助,因为
leafs都是同一类型...
标签: sql postgresql database-design