如何在数据库表的行层次结构中建模和查询继承?

时间:2009-08-28 13:17:24

标签: database database-design inheritance

我有一组记录,存储为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继承“品味如鸡”的值。

由于我不是任何条纹的大师,我对如何最好地使用系统有几个疑问。

  1. 由于我需要能够以原始格式从数据库导出,所以我不能简单地预先计算和缓存“丢失”记录。或者我可以吗?请注意,缓存可能有点智能,因为更新可能会更改Foo中应该传播到Bar1和Bar2的值。

  2. 是否有标准的数据库工具或SQL参数可以在一个(或相对较少的)查询中正确“构建”条形记录?我知道常见的表表达式,似乎这是解决方案的一半,但这将返回行树,然后需要进一步处理以适当地填写所有属性。

  3. 他们是否有其他使用此类数据和数据库结构的提示和行程?也许这是一个愚蠢的问题,但我没有任何正式的编程教育,所以很多概念对我来说都是新的。

  4. 请注意,不可能为各个分支创建单独的表,因为树可以具有任意深度。预期的树木大小约为3000个儿童记录,树木深度为3层,存储数千棵树。

    我正在使用Django,如果这很重要,但我对使用原始SQL查询感到非常舒服(例如,我构建了一个Django应用程序来操作directed acyclic graphs,它主要使用原始SQL,因为复杂的分组和有条款)。

1 个答案:

答案 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个问题,我希望能够在本周末发布一个存储树木的替代方案。否则我会说你的想法对我很好。