我正在使用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) );
答案 0 :(得分:1)
使用触发器。
一般来说,Postgres开发人员不建议在CHECK约束中放置运行查询的函数。除此之外,在某些情况下,对于查询,可能会多次检查CHECK约束,这是一个相当昂贵的检查。更重要的是,对于行可见性和触发器的类似注意事项,有很多仔细的工程设计,对于约束条件而言根本就不存在。
我还建议您考虑另一种方法:如果使用BEFORE触发器,忽略用户输入,并自动为新节点提供与其父节点相同的group_id,而不是抛出错误?
或者甚至更好,因为group_ids与父母有关系而不与子女有关,如何将group_ids放在一个单独的表中,该表只链接到父节点?