我有一组记录,存储为XML文件,其中XML文件以树形结构排列。对于每个子记录,假定未明确声明的元素或属性从父记录继承。这很容易在数据库中建模,具有自引用外键,例如
Foo
/ \
Bar1 Bar2
id | parent_id | name | attribute 1 | attribute 2
1 | null | Foo | 0.4 | "tastes like chicken"
2 | 1 | Bar 1 | null | "doesn't everything"
3 | 1 | Bar 2 | 0.2 | null
(在生产中我会使用一个额外的列来存储树结构,但为了简单起见,这是省略的。)
在这个系统中,Bar1将为属性1继承值0.4,而Bar2将为属性2继承“品味如鸡”的值。
由于我不是任何条纹的大师,我对如何最好地使用系统有几个疑问。
由于我需要能够以原始格式从数据库导出,所以我不能简单地预先计算和缓存“丢失”记录。或者我可以吗?请注意,缓存可能有点智能,因为更新可能会更改Foo中应该传播到Bar1和Bar2的值。
是否有标准的数据库工具或SQL参数可以在一个(或相对较少的)查询中正确“构建”条形记录?我知道常见的表表达式,似乎这是解决方案的一半,但这将返回行树,然后需要进一步处理以适当地填写所有属性。
他们是否有其他使用此类数据和数据库结构的提示和行程?也许这是一个愚蠢的问题,但我没有任何正式的编程教育,所以很多概念对我来说都是新的。
请注意,不可能为各个分支创建单独的表,因为树可以具有任意深度。预期的树木大小约为3000个儿童记录,树木深度为3层,存储数千棵树。
我正在使用Django,如果这很重要,但我对使用原始SQL查询感到非常舒服(例如,我构建了一个Django应用程序来操作directed acyclic graphs,它主要使用原始SQL,因为复杂的分组和有条款)。
答案 0 :(得分:1)
您没有指定数据库,但查看指向非循环图的链接,我看到您使用的是PostgreSQL。如果您能够使用最新版本8.4,您可以尝试以下(应该回答您的第二个问题):
使用表格
create table Tree(
id serial primary key check(id > 0),
parent int references Tree(id),
name varchar(100) not null unique check(length(name)>0),
attr1 int,
attr2 varchar(15),
constraint charlength check(id > parent)
);
填写此数据
insert into Tree (name, parent, attr1, attr2)
values ('Foo', null, 5, 'high'), -- will have id 1
('Bar1', 1, null, 'low'), -- will have id 2
('Bar2', 1, null, null),
('Bar3', 2, null, null);
查询
with recursive parents(id, name, attr1, attr2, parent, level, who) as (
select id, name, attr1, attr2, parent, 1, id
from Tree t
where t.name in ('Bar3', 'Bar2')
union all
select t.id, p.name, coalesce(p.attr1, t.attr1), coalesce(p.attr2, t.attr2), t.parent, p.level+1, p.who
from parents p, Tree t
where t.id = p.parent
) select distinct on (who) who, name, attr1, attr2
from parents
order by who, level desc;
产生(用我的ruby程序包装查询):
{"attr1"=>"5", "name"=>"Bar2", "attr2"=>"high", "who"=>"3"}
{"attr1"=>"5", "name"=>"Bar3", "attr2"=>"low", "who"=>"4"}
关于你的第一个问题我不确定你的意思。但也许你可以从数据库中的表示中恢复XML?!?对于你的第3个问题,我希望能够在本周末发布一个存储树木的替代方案。否则我会说你的想法对我很好。