我有一个表,称之为EVENTS,其中每行可以依赖于表中的0个或更多其他行。我需要一种表示这种关系的方法,这种方式也可以防止循环依赖(即一组事件导回同一组中的事件)。
我目前在EVENTS外部有一个链接表,称之为EVENTS_DEP。此表将依赖行链接到它们所依赖的行,并允许在一行上存在多个依赖项。如何使用这样的表防止循环依赖?
注意:如果完全可以只使用数据库设计(不使用脚本,触发器等),这将是理想的。
另外,如果只能使用触发器进行此操作,请告诉我应该运行什么类型的触发器(即在什么事件上)(插入时,可能?)。
答案 0 :(得分:6)
INSERT触发器检查这一点。
假设有以下表格结构
CREATE TABLE event (
id bigserial PRIMARY KEY,
foo varchar
);
CREATE TABLE event_deps (
parent bigint REFERENCES event(id),
child bigint REFERENCES event(id),
PRIMARY KEY (parent, child),
CHECK (parent <> child)
);
需要以下INSERT触发器
CREATE FUNCTION deps_insert_trigger_func() RETURNS trigger AS $BODY$
DECLARE
results bigint;
BEGIN
WITH RECURSIVE p(id) AS (
SELECT parent
FROM event_deps
WHERE child=NEW.parent
UNION
SELECT parent
FROM p, event_deps d
WHERE p.id = d.child
)
SELECT * INTO results
FROM p
WHERE id=NEW.child;
IF FOUND THEN
RAISE EXCEPTION 'Circular dependencies are not allowed.';
END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER before_insert_event_deps_trg BEFORE INSERT ON event_deps
FOR EACH ROW
EXECUTE PROCEDURE deps_insert_trigger_func();
它的作用是在父A和子B之间添加新链接时,它使用A WITH RECURSIVE查询来查找A的所有祖先.B不应该是其中之一。
UPDATE触发器更难,因为当执行触发器仍然存在旧链接时,INSERT触发器的测试在用于UPDATE时会产生误报。
因此,对于UPDATE,我们需要添加一些额外的条件来隐藏旧数据。
CREATE FUNCTION deps_update_trigger_func() RETURNS trigger AS $BODY$
DECLARE
results bigint;
BEGIN
WITH RECURSIVE p(id) AS (
SELECT parent
FROM event_deps
WHERE child=NEW.parent
AND NOT (child = OLD.child AND parent = OLD.parent) -- hide old row
UNION
SELECT parent
FROM p, event_deps d
WHERE p.id = d.child
AND NOT (child = OLD.child AND parent = OLD.parent) -- hide old row
)
SELECT * INTO results
FROM p
WHERE id=NEW.child;
IF FOUND THEN
RAISE EXCEPTION 'Circular dependencies are not allowed.';
END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER before_update_event_deps_trg BEFORE UPDATE ON event_deps
FOR EACH ROW
EXECUTE PROCEDURE deps_update_trigger_func();
答案 1 :(得分:1)
使用SQL引擎并且没有编程触发器是不可能的。对于支持这种情况的SQl引擎,它需要支持递归SQL(也就是递归的WITH表达式或递归CTE),以及对ASSERTION的可靠支持。
许多人都支持CTE的/ WITH表达式,但也许并非所有人都支持该功能的递归版本。至于ASSERTIONs otoh,我被告知只有一个系统支持它们,但是实现是如此有缺陷和错误,以至于认真考虑使用它是可笑的。
有些系统允许您完全按照您的要求执行操作,但不要指望将SQL与此类系统对话。这些系统的作者为保持婴儿关系而感到自豪。