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

您用来对数据库中的层次结构信息进行建模和检索的方式是什么?

9个解决方案
31 votes

我喜欢修改后的预排序树遍历算法。 此技术使查询树变得非常容易。

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

许多链接与语言无关:

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

  • 嵌套集,也称为修改的预序树遍历算法
  • 邻接表模型

在这里有很好的解释:

  • [HTTP://呜呜呜.site point.com/article/hierarchical-data-database]
  • 在MySQL中管理分层数据
  • [HTTP://呜呜呜.EVO Lt.org/article/four_ways_to_work_with_hierarchical_data/17/4047/index.HTML]

这是我收集的更多链接:

  • [HTTP://恩.Wikipedia.org/wiki/tree_%28data_structure%29]
  • [HTTP://恩.Wikipedia.org/wiki/category:trees_%28structure%29]

邻接表模型

  • [HTTP://呜呜呜.SQL team.com/item.asp?item ID=8866]

嵌套集

  • [HTTP://呜呜呜.SQL summit.com/adjacency list.htm]
  • [HTTP://呜呜呜.额度特产.吃/contribution/NS trees/index.PHP]
  • [HTTP://呜呜呜.PHP riot.com/的/articles/PHP/application-design/nested-trees-1/]
  • [HTTP://呜呜呜.DBMS mag.com/9604的06.HTML]
  • [HTTP://恩.Wikipedia.org/wiki/tree_traversal]
  • [http://www.cosc.canterbury.ac.nz/mukundan/dsal/BTree.html](显示其工作方式的Java小程序)

图表

  • [HTTP://呜呜呜.artful software.com/MySQL book/sampler/MySQL Ed1吃20.HTML]

课程:

嵌套集数据库树Adodb

  • [HTTP://呜呜呜.PHP classes.org/browse/package/2547.HTML]

访问模型ADOdb

  • [HTTP://呜呜呜.PHP classes.org/browse/package/2919.HTML]

PEAR :: DB NestedSet

  • [HTTP://pear.PHP.net/package/dB_nested set]
  • 用法:[https://www.entwickler.com/itr/kolumnen/psecom,id,26,nodeid,207.html]

梨树

  • [HTTP://pear.PHP.net/package/tree/download/0.3.0/]
  • [HTTP://呜呜呜.PHP kitchen.com/index.PHP?/archives/337-pear tree-tutorial.HTML]

nstrees

  • [HTTP://呜呜呜.额度特产.吃/contribution/NS trees/index.PHP]
markus answered 2020-06-29T19:11:54Z
14 votes

关于这一主题的确定性文章是由Joe Celko撰写的,他已经将其中的许多著作写成了《 Joe Celko的SQL for Smarties的树和层次结构》一书。

他赞成一种称为有向图的技术。 在此可以找到他在该主题上的工作简介。

andy47 answered 2020-06-29T19:08:56Z
10 votes

在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

现在,您可以运行不涉及将表本身重新联接起来的任意查询,如果您在与节点相同的行中具有层次结构关系,则可能会发生这种查询。

谁有祖父母?

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个子查询。

麻烦的是,维护祖先表有点困难-最好通过存储过程来完成。

Josh answered 2020-06-29T19:13:03Z
9 votes

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

该查询(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;
NakedBrunch answered 2020-06-29T19:13:28Z
4 votes

仅供参考:SQL Server 2008针对这种情况引入了新的HierarchyID数据类型。 使您可以控制行在水平和垂直方向上在“树”中的位置。

Matt Hamilton answered 2020-06-29T19:13:48Z
3 votes

Oracle:选择...以...开始...以...连接

Oracle对SELECT进行了扩展,可以轻松进行基于树的检索。 也许SQL Server具有类似的扩展名?

该查询将遍历嵌套关系存储在父列和子列中的表。

select * from my_table
    start with parent = :TOP
    connect by prior child = parent;

[HTTP://呜呜呜.ADP-关门闭户.吃/Ora/SQL/connect_不要.HTML]

Mark Harrison answered 2020-06-29T19:14:21Z
2 votes

我更喜欢Josh和Mark Harrison使用的各种技术:

两个表,一个表包含Person的数据,另一个表包含层次结构信息(person_id,parent_id [,mother_id])(如果此表的PK为person_id),则您有一棵简单的树,其中每个节点只有一个父树(在 在这种情况下,但在其他情况下(例如会计帐户)则没有)

可以通过递归过程或如果您的数据库通过诸如SELECT ... BY PRIOR(Oracle)之类的语句来支持此层次结构表。

另一种可能性是,如果您知道要维护的层次结构数据的最大深度是使用单个表,并且每个层次结构级别具有一组列

Telcontar answered 2020-06-29T19:14:55Z
1 votes

当我们为[fleXive]实现树组件并使用MySQL文档中tharkun提到的嵌套集树模型方法时,我们遇到了同样的问题。

除了(以戏剧性的方式)加快速度之外,我们还使用了分散的方法,这仅意味着我们对顶层右边界使用了最大的Long值,这使我们能够插入和移动节点而无需重新计算所有的left和right值。 左和右的值是通过将节点的范围除以3并使用内部的三分之一作为新节点的边界来计算的。

在这里可以看到一个Java代码示例。

Markus Plesser answered 2020-06-29T19:15:24Z
0 votes

如果您使用的是SQL Server 2005,则此链接说明如何检索分层数据。

只要您习惯使用通用表表达式(CTE),它们就可以成为您的朋友。

NakedBrunch answered 2020-06-29T19:15:49Z
translate from https://stackoverflow.com:/questions/38801/sql-how-to-store-and-navigate-hierarchies