2015-06-08 30 views
0

我是SQL新手,想对以下问题提供任何帮助。我有以下代码为节点和树创建表,但不知道如何在我的代码中实现以下规则。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 
 
\t add constraint FK_NodeNode foreign key(ParentId) references Node(NodeId) --on delete cascade; 
 

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

设想一个树结构,具有以下性质:

  • A)单一根节点
  • b)每个节点可以具有多个子节点
  • c)节点可能不是d e)所有非根节点都有一个属性,最多的子节点 - 新节点默认为固定默认值
  • e)最大子节点属性可随时更改 - 如果新值较小比当前的儿童节点数量多,孩子们分布在沿途所有节点的财产链中。如果该属性设置为零,则该节点成为根节点的直接子节点。
  • f)当添加一个新节点时,它将被添加到尽可能接近根节点的节点,按照儿童百分比配额排序递增。如果所有节点都满足其配额,则直接放置在根节点下。

创建表和索引来存储这些信息和程序,以尽可能有效地执行以下操作:

  • 我。将节点添加到树
  • ii。更改节点的最大子节点属性
+0

我不知道如何设置列出的约束条件(如节点可能不会被删除)。像我可以以某种方式在表格创建中定义这些约束吗? –

+0

防止删除通常通过触发器完成。 – RedFilter

+0

老实说,我昨天就开始使用SQL,所以我拥有的就是使用谷歌和阅读其他论坛的想法。我真的不知道关于外键的任何信息。但我认为ParentId应该不为null。 –

回答

1

并非所有约束都可以在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 
+0

谢谢!我有一个关于MaxChild的问题 - 为什么默认设置为-1?我能否改变这种情况并将其用作约束来限制父节点可以拥有的子节点的数量?在应用程序中执行某些部分的含义是什么?对不起,如果这些都是愚蠢的问题。 –

+0

@MelanieThorn是的,你可以设置'MaxChild',设置-1为默认意味着对子节点的数量没有限制。 “MaxChild”的用法可以在“SQL触发器”或应用程序中定义,可以是C#/ SQL查询 - 它使用SQL语句来操作节点。 – Eric