当前位置:  开发笔记 > 数据库 > 正文

SQL - 如何存储和导航层次结构?

如何解决《SQL-如何存储和导航层次结构?》经验,为你挑选了4个好方法。

您在数据库中建模和检索分层信息的方式有哪些?



1> markus..:

我喜欢Modified Preorder Tree Traversal算法.这种技术使查询树变得非常容易.

但是这里有一个关于这个主题的链接列表,我从Zend Framework(PHP)贡献者网页上复制了这个主题(由Laurent Melmoux发布于2007年6月5日15:52).

许多链接都是语言无关的:

有两种主要的表示和算法来表示具有数据库的层次结构:

嵌套集也称为修改前序树遍历算法

邻接表模型

这里有很好的解释:

http://www.sitepoint.com/article/hierarchical-data-database

在MySQL中管理分层数据

http://www.evolt.org/article/Four_ways_to_work_with_hierarchical_data/17/4047/index.html

以下是我收集的一些链接:

http://en.wikipedia.org/wiki/Tree_%28data_structure%29

http://en.wikipedia.org/wiki/Category:Trees_%28structure%29

邻接表模型

http://www.sqlteam.com/item.asp?ItemID=8866

嵌套集

http://www.sqlsummit.com/AdjacencyList.htm

http://www.edutech.ch/contribution/nstrees/index.php

http://www.phpriot.com/d/articles/php/application-design/nested-trees-1/

http://www.dbmsmag.com/9604d06.html

http://en.wikipedia.org/wiki/Tree_traversal

http://www.cosc.canterbury.ac.nz/mukundan/dsal/BTree.html(applet java montrant le fonctionnement)

Graphes

http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html

课程:

嵌套集DB树Adodb

http://www.phpclasses.org/browse/package/2547.html

访问模型ADOdb

http://www.phpclasses.org/browse/package/2919.html

PEAR :: DB_NestedSet

http://pear.php.net/package/DB_NestedSet

利用率:https://www.entwickler.com/itr/kolumnen/psecom,id,26,nodeid,207.html

梨树

http://pear.php.net/package/Tree/download/0.3.0/

http://www.phpkitchen.com/index.php?/archives/337-PEARTree-Tutorial.html

nstrees

http://www.edutech.ch/contribution/nstrees/index.php



2> andy47..:

关于这个主题的权威部分是由Joe Celko编写的,他已经将其中的一些作品编写成了一本名为Joe Celko的树和层次结构的SQL for Smarties.

他赞成一种称为有向图的技术.可在此处找到他关于此主题的工作介绍


我以为人们称这种技术为"嵌套集".

3> Josh..:

在SQL数据库中表示层次结构的最佳方法是什么?一种通用的便携式技术?

我们假设层次结构主要是读取的,但不是完全静态的.让我们说这是一棵家谱.

这是不怎么做:

create table person (
person_id integer autoincrement primary key,
name      varchar(255) not null,
dob       date,
mother    integer,
father    integer
);

并插入如下数据:

person_id   name      dob       mother father  
1           Pops      1900/1/1   null   null  
2           Grandma   1903/2/4   null   null  
3           Dad       1925/4/2   2      1  
4           Uncle Kev 1927/3/3   2      1
5           Cuz Dave  1953/7/8   null   4
6           Billy     1954/8/1   null   3

相反,将节点和关系拆分为两个表.

create table person (
person_id integer autoincrement primary key,
name      varchar(255) not null,
dob       date
);

create table ancestor (
ancestor_id   integer,
descendant_id integer,
distance      integer
);

数据创建如下:

person_id   name      dob       
1           Pops      1900/1/1  
2           Grandma   1903/2/4   
3           Dad       1925/4/2   
4           Uncle Kev 1927/3/3
5           Cuz Dave  1953/7/8   
6           Billy     1954/8/1   

ancestor_id  descendant_id  distance
1            1              0
2            2              0
3            3              0
4            4              0
5            5              0
6            6              0
1            3              1
2            3              1
1            4              1
2            4              1
1            5              2
2            5              2
4            5              1
1            6              2
2            6              2
3            6              1

现在,您可以运行不涉及将表连接回自身的仲裁查询,如果您在与节点相同的行中具有heirachy关系,则会发生这种情况.

谁有祖父母?

select * from person where person_id in 
    (select descendant_id from ancestor where distance=2);

你所有的后代:

select * from person where person_id in 
    (select descendant_id from ancestor 
    where ancestor_id=1 and distance>0);

谁是叔叔?

select decendant_id uncle from ancestor 
    where distance=1 and ancestor_id in 
    (select ancestor_id from ancestor 
        where distance=2 and not exists
        (select ancestor_id from ancestor 
        where distance=1 and ancestor_id=uncle)
    )

您可以避免通过子查询将表连接到自身的所有问题,常见的限制是16个子查询.

麻烦的是,维护祖先表有点难 - 最好用存储过程完成.



4> NakedBrunch..:

我不得不同意乔希.如果您使用像公司组织这样的庞大层级结构会发生什么.人们可以加入/离开公司,更改报告行等...维持"距离"将是一个大问题,您将不得不维护两个数据表.

此查询(SQL Server 2005及更高版本)将允许您查看任何人的完整行并计算它们在层次结构中的位置,并且它只需要一个用户信息表.可以修改它以查找任何子关系.

--Create table of dummy data
create table #person (
personID integer IDENTITY(1,1) NOT NULL,
name      varchar(255) not null,
dob       date,
father    integer
);

INSERT INTO #person(name,dob,father)Values('Pops','1900/1/1',NULL);  
INSERT INTO #person(name,dob,father)Values('Grandma','1903/2/4',null);
INSERT INTO #person(name,dob,father)Values('Dad','1925/4/2',1);
INSERT INTO #person(name,dob,father)Values('Uncle Kev','1927/3/3',1);
INSERT INTO #person(name,dob,father)Values('Cuz Dave','1953/7/8',4);
INSERT INTO #person(name,dob,father)Values('Billy','1954/8/1',3);

DECLARE @OldestPerson INT; 
SET @OldestPerson = 1; -- Set this value to the ID of the oldest person in the family

WITH PersonHierarchy (personID,Name,dob,father, HierarchyLevel) AS
(
   SELECT
      personID
      ,Name
      ,dob
      ,father,
      1 as HierarchyLevel
   FROM #person
   WHERE personID = @OldestPerson

   UNION ALL

   SELECT
    e.personID,
      e.Name,
      e.dob,
      e.father,
      eh.HierarchyLevel + 1 AS HierarchyLevel
   FROM #person e
      INNER JOIN PersonHierarchy eh ON
         e.father = eh.personID
)

SELECT *
FROM PersonHierarchy
ORDER BY HierarchyLevel, father;

DROP TABLE #person;

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有