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

Database 如何在数据库表中的行层次结构中建模和查询继承?,database,database-design,inheritance,Database,Database Design,Inheritance,我有一组记录,存储为XML文件,其中XML文件以树结构排列。对于每个子记录,假定未明确说明的元素或属性从父记录继承。这很容易在数据库中建模,使用自引用外键,例如 树形结构 数据库表 (在生产中,我会使用一个或多个列来存储树结构,但为了简单起见,省略了这一点。) 在这个系统中,Bar1将为属性1继承一个值0.4,Bar2将为属性2继承一个值“味道像鸡” 由于我远非任何领域的大师,我有几个关于如何最好地使用系统的问题 因为我需要能够以原始格式从数据库导出,所以我不能简单地预先计算和缓存“丢失”的

我有一组记录,存储为XML文件,其中XML文件以树结构排列。对于每个子记录,假定未明确说明的元素或属性从父记录继承。这很容易在数据库中建模,使用自引用外键,例如

树形结构
数据库表
(在生产中,我会使用一个或多个列来存储树结构,但为了简单起见,省略了这一点。)

在这个系统中,Bar1将为属性1继承一个值0.4,Bar2将为属性2继承一个值“味道像鸡”

由于我远非任何领域的大师,我有几个关于如何最好地使用系统的问题

  • 因为我需要能够以原始格式从数据库导出,所以我不能简单地预先计算和缓存“丢失”的记录。或者我可以吗?请注意,缓存在某种程度上是智能的,因为更新可能会更改Foo中的值,这些值应该向下传播到Bar1和Bar2

  • 是否有标准的数据库工具或SQL参数可以在一次(或相对较少的)查询中“构建”Bar记录?我知道常见的表表达式,看起来这是解决方案的一半,但这将返回行树,然后需要进一步处理以适当地填充所有属性

  • 他们是否还有其他使用这种数据和数据库结构的技巧和经验?也许这是一个愚蠢的问题,但我没有受过任何正规的编程教育,所以很多概念对我来说都是全新的

  • 请注意,不可能为各个分支创建单独的表,因为树可以具有任意深度。预计树的大小约为3000个子记录,一棵树有3层深,需要存储数千棵树


    我正在使用Django,如果这很重要的话,但我对原始SQL查询的处理还不太满意(例如,我构建了一个Django应用程序来操作,由于复杂的GROUPBY和having子句,它主要使用原始SQL)。

    您没有指定您的数据库,但是看看你的有向无环图链接,我发现你使用的是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程序包装查询):


    关于你的第一个问题,我不知道你的意思。但也许您可以从数据库中的表示恢复XML?!?对于你的第三个问题,我希望能在这个周末发布一个储存树木的替代方案。否则我会说你的想法对我来说很好。

    谢谢你。公共表表达式和合并的结合非常完美。我最喜欢的存储树的方法是用unicode字符串(utf-8)对树中的位置进行编码,父级是通过删除最后一个unicode字符获得的字符串(在PostgreSQL:substring中(treepos from 1表示字符长度(treepos)-1))。如果你想了解更多,请告诉我。
    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;
    
    {"attr1"=>"5", "name"=>"Bar2", "attr2"=>"high", "who"=>"3"}
    {"attr1"=>"5", "name"=>"Bar3", "attr2"=>"low", "who"=>"4"}