2

我正在尝试找到一种将记录插入表的方法,该表使用新生成的 Identity 值作为其层次结构 ID 的一部分。以下 sql 演示了我正在尝试做的事情,以及我设法做到的最接近的事情。这是在事务内部使用插入后跟更新。我在想出初始层次结构 id 时遇到了麻烦,因为该字段有一个唯一的约束,我担心如果同时将 2 个元素添加到同一个父级,可能会引发错误。

DECLARE @hierarchy_elements TABLE (
     id int IDENTITY (1, 1) NOT NULL ,
     element_path hierarchyid NOT NULL
)

-- Cheating here, but I need some data to append to.
INSERT INTO @hierarchy_elements(element_path)
SELECT ('/1/')
UNION ALL SELECT ('/1/2/')

-- See that we have a couple elements in the table.
SELECT id, element_path.ToString() as [path] from @hierarchy_elements

-- arbitrarily pick a parent to append to
DECLARE @parentElementId int = 2

-- grab that parent's path.
DECLARE @parentElementPath hierarchyid 
SELECT @parentElementPath = element_path FROM @hierarchy_elements WHERE id = @parentElementId

-- This is what I want to do.  Use the current id as the last part of the hierarchyid
INSERT INTO @hierarchy_elements (element_path)
VALUES(@parentElementPath.ToString() + CAST(scope_identity() AS VARCHAR(20)) + '/')

-- This works, but kind of sucks.
BEGIN TRANSACTION 

-- Insert under the parent with a known invalid id.
INSERT INTO @hierarchy_elements (element_path)
VALUES(@parentElementPath.ToString() + '-1/')

-- now update setting the last element in the hierarchyid to the id just generated.
UPDATE @hierarchy_elements 
SET element_path = @parentElementPath.ToString() + CAST(SCOPE_IDENTITY() AS VARCHAR(20)) + '/'
WHERE id = SCOPE_IDENTITY()

COMMIT TRANSACTION

-- See that id 3 would fail the unique constraint check, but id 4 is correct.
SELECT id, element_path.ToString() as [path] from @hierarchy_elements

如果可能的话,我想使用单个语句插入,该语句将在 hierarchyid 字段中包含新的 Identity 值。

4

1 回答 1

1

解决问题的总体思路:

单独生成行的ID,记住某处,然后将生成的ID原样插入ID列,并使用相同的记忆值组成element_path.

如果您使用 SQL Server 2012 及更高版本,它有一个SEQUENCE功能。如果您使用的是 2008 及以下版本,则可以有一个单独的专用表,其中包含一个IDENTITY用于生成 ID 的列。

所以你的主表的结构会有所不同(id 不再是IDENTITY):

DECLARE @hierarchy_elements TABLE (
     id int NOT NULL ,
     element_path hierarchyid NOT NULL
)

并且您将有一个单独的对象(SEQUENCE或辅助表)来根据需要生成唯一 ID。

您将有一个生成 ID 的额外显式步骤,但您可以只将一个 IDINSERT放入主表中,而无需UPDATE.

第二种变体

您可以使用 anAFTER INSERT TRIGGER来“隐藏”显式UPDATE语句。此变体非常接近您的原始方法。您仍然需要在element_path. 该“某事”将在触发器中使用新生成的 ID by 进行调整IDENTITY

于 2015-01-28T02:23:08.947 回答