我使用邻接表模型将嵌套列表存储在我的数据库中。每个列表可能有 50-150 个节点,所以我们称它为平均 100 个节点。出现了用户想要克隆列表的情况(即,使用现有列表作为模板,从中创建新列表)。当新列表与现有列表仅略有不同时,此用例可能会为他们节省大量时间。
这是我正在使用的表架构的简化版本:
CREATE TABLE Nodes (
NodeId int IDENTITY(1,1) NOT NULL,
ParentId int NULL,
ListId int NOT NULL,
NodeText varchar(255) NOT NULL
)
我最初的想法是使用 INSERT ... SELECT
一次性复制所有节点,但这会使新记录引用旧的 ParentId
值。
我有一个有效的解决方案(在应用程序代码中,而不是在 SQL 中),但由于所需的查询数量,它似乎不是最佳选择。这是算法:
- 选择属于旧列表的所有记录。
- 遍历行并通过插入不同的
ListId
来添加到新列表。 - 从每个插入中选择
@@IDENTITY
并将其与当前行的数据一起存储。 - 再次遍历行并更新
Nodes
表,将ParentId
设置为新 ID(来自上一步),其中ParentId
等于旧 IDListId
等于新的列表 ID。
正如我所说,这很好用,但它需要 300 多个查询才能克隆包含 100 个节点的单个列表。有没有更有效的方法来实现同样的事情?
最佳答案
试试这个。以下解决方案是零循环、零临时表一。
DECLARE @CurrentID int = IDENT_CURRENT('Nodes'),
@OldListId int = 1,
@NewListId int;
SELECT @NewListId = ISNULL(MAX(ListId) ,0)+1 FROM Nodes
SET IDENTITY_INSERT Nodes ON
;WITH NewNode as (
SELECT ROW_NUMBER() OVER(ORDER BY NodeId)+ @CurrentID as NewNodeId, *
FROM Nodes WHERE ListId= @OldListId
)
INSERT INTO Nodes(NodeId,ParentId,ListId,NodeText)
SELECT N1.NewNodeId ,N2.NewNodeId , @NewListId, N1.NodeText FROM NewNode N1 LEFT OUTER JOIN NewNode N2 ON
N1.ParentId = N2.NodeId
--SELECT N1.* , N2.NewNodeId as NewParentId FROM NewNode N1 LEFT OUTER JOIN NewNode N2 ON
--N1.ParentId = N2.NodeId
SET IDENTITY_INSERT Nodes OFF
上述解决方案生成树,然后插入到表中。请注意使用适当的事务和锁定机制以确保数据一致
关于sql - 在邻接表模型中克隆树的数据库表示的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20338268/