SQL树结构表

时间:2015-06-08 01:04:06

标签: sql sql-server tree nodes

我是SQL新手,希望对以下问题有任何帮助。我有以下代码为节点和树创建一个表,但不知道如何在我的代码中实现以下规则。

create table Node(
    NodeId int not null,
    ParentId int null,
    NodeName varchar(255) not null,
    constraint PK_Node primary key(NodeId),
    constraint UK_NodeName unique(NodeName)
)
go

create table Tree(
    NodeId int not null,
    ParentId int not null,
    Level int not null,
    constraint PK_Tree primary key(NodeId, ParentId),
    constraint UK_Level unique(NodeId, Level)
)
go}



alter table Node
	add constraint FK_NodeNode foreign key(ParentId) references Node(NodeId) --on delete cascade;

alter table Tree
	add constraint FK_NodeTreeNode foreign key(NodeId) references Node(NodeId) on delete cascade;




想象一下具有以下属性的树结构:

  • a)单根节点
  • b)每个节点可能有多个子节点
  • c)节点不得删除
  • d)所有非根节点都有一个属性max children nodes - 新节点默认为固定的默认值
  • e)可以随时更改max children nodes属性 - 如果新值小于当前子节点数,则子节点将沿着链路向上分布,该链路遵循该路径上所有节点的属性。如果该属性设置为零,则该节点将成为根节点的直接子节点
  • f)添加新节点时,会将其添加到节点,尽可能接近根级别按递增子节点的百分比排序。如果所有节点都满足其配额,则将其直接放在根节点下。

创建表和索引以存储此信息和过程,以尽可能高效地执行以下操作:

  • 我。将节点添加到树
  • II。更改节点的max children node属性

1 个答案:

答案 0 :(得分:2)

并非所有约束都可以在SQL Server中设置。 a,d,e,f的逻辑应该适用于应用程序。

树只是Nodes的组合。所以我们只需要定义Node的存储空间。

create table Node(
    NodeId int not null identity(1,1), -- Identity, auto generate Id for new Node
    ParentId int null, -- If null, it is the root of the tree
    MaxChild int not null default(-1),
    NodeName varchar(255) not null,
    constraint PK_Node primary key(NodeId),
    constraint UK_NodeName unique(NodeName),
    constraint FK_Node foreign key(ParentId) references Node(NodeId) 
    -- How the `Node` to be related and form the tree can be done 
    -- by adding the `Foreign Key` of `Node` itself
    -- A node cannot be simply deleted if it is a parent.
)

添加节点:

-- Add root
insert Node (NodeName) VALUES ('root')

-- Add child
insert Node (ParentId, NodeName) VALUES 
((SELECT NodeId FROM Node WHERE NodeName = 'Root'), 'ChildA')

insert Node (ParentId, NodeName) VALUES 
((SELECT NodeId FROM Node WHERE NodeName = 'Root'), 'ChildB')

insert Node (ParentId, NodeName) VALUES 
((SELECT NodeId FROM Node WHERE NodeName = 'ChildA'), 'ChildA-A')

insert Node (ParentId, NodeName) VALUES 
((SELECT NodeId FROM Node WHERE NodeName = 'ChildA-A'), 'ChildA-A-A')

获取Nodes和子计数

的级别
;WITH 
CountLevel AS
(
    SELECT *, 1 AS Level FROM Node WHERE ParentId IS NULL

    UNION ALL

    SELECT child.*, parent.Level + 1 
    FROM Node child INNER JOIN CountLevel parent ON 
        child.ParentId = parent.NodeId
), 
CountChild AS
(
    SELECT NodeId, ParentId, 0 AS ChildCount 
    FROM Node leaf 
    WHERE NOT EXISTS(SELECT * FROM Node WHERE ParentId = leaf.NodeId)

    UNION ALL

    SELECT child.ParentId, (SELECT ParentId FROM Node WHERE NodeId = child.ParentId), child.ChildCount + 1 
    FROM CountChild child
    WHERE child.ParentId IS NOT NULL
)
SELECT *, (SELECT SUM(ChildCount) FROM CountChild WHERE NodeId = CountLevel.NodeId) Child FROM CountLevel

结果

NodeId      ParentId    MaxChild    NodeName             Level       Child
----------- ----------- ----------- -------------------- ----------- -----------
1           NULL        -1          Root                 1           4
2           1           -1          ChildA               2           2
3           1           -1          ChildB               2           0
4           2           -1          ChildA-A             3           1
5           4           -1          ChildA-A-A           4           0