【问题标题】:SQL Tree Structure TableSQL 树结构表
【发布时间】:2015-06-08 01:04:05
【问题描述】:

我是 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) 可以随时更改最大子节点属性 - 如果新值小于当前子节点数,则子节点将按照沿途所有节点的属性沿链向上分布。如果该属性设置为零,则该节点将成为根节点的直接子节点
  • f) 添加新节点时,它会添加到尽可能接近根级别的节点,按填充的子节点百分比配额升序排列。如果所有节点都达到了配额,则将其直接置于根节点之下。

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

  • i.向树中添加节点
  • 二。更改节点的最大子节点属性

【问题讨论】:

  • 我不确定如何设置列出的约束(比如节点可能不会被删除)。像我可以以某种方式在表创建中定义这些约束吗?
  • 防止删除通常是通过触发器完成的。
  • 老实说,我昨天开始使用 SQL,所以我所拥有的是我使用 google 和阅读其他论坛的结果。我对外键一无所知。我认为 ParentId 不应该为空。

标签: sql sql-server tree nodes


【解决方案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

【讨论】:

  • 谢谢!我有一个关于 MaxChild 的问题 - 为什么默认设置为 -1?我可以更改它并将其用作限制父节点可以拥有的子节点数量的约束吗?在应用程序中完成的某些部分是什么意思?抱歉,如果这些问题中的任何一个都是愚蠢的问题。
  • @MelanieThorn 是的,您可以设置MaxChild,将 -1 设置为默认值意味着对子节点的数量没有限制。 MaxChild 的用法可以在SQL Trigger 中定义,也可以在您的应用程序中定义,可以是 C#/SQL 查询——它使用 SQL 语句来操作节点。
猜你喜欢
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 2020-01-12
  • 2013-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多