我有一个递归的CTE,它给出了一组父级子键的列表,如下所示,让我们在一个名为#relationtree的临时表中这样说
Parent | Child
--------------
1 | 3
3 | 5
5 | 6
5 | 9
我想要创建这些关系的副本到一个表中,比如说,下面的结构:
CREATE TABLE [dbo].[Relations]
(
[Id] int identity(1,1)
[ParentId] int
)
我如何插入上述记录,但递归地获得先前插入的标识值,以便能够将该值作为我插入的每个子副本的ParentId列插入?
在dbo.Relations中,我希望在此结束时
Id | ParentId
-------------
... other rows present before this query ...
50 | NULL
51 | 50
52 | 51
53 | 51
我不确定scope_identity是否能够在这种情况下工作,或者是否使用新is列表创建新的临时表并手动插入标识列是正确的方法?
我可以编写一个游标/循环来完成这个任务,但是必须有一种很好的方法来执行递归选择魔术!
发布于 2016-04-26 10:33:09
由于您试图将树放入表的一个段中,所以看起来无论如何您都需要对表使用SET IDENTITY_INSERT ON
。你需要确保这棵新树有空间。在本例中,我将假设49是表中当前的最大id
,这样我们就不需要担心超出表后面的树了。
您需要能够将ID从旧树映射到新树。除非‘d有一些规则,精确的映射应该是不相关的,只要它是准确的,所以在这种情况下,我只需要这样做:
SET IDENTITY_INSERT dbo.Relations ON
;WITH CTE_MappedIDs AS
(
SELECT
old_id,
ROW_NUMBER() OVER(ORDER BY old_id) + 49 AS new_id
FROM
(
SELECT DISTINCT parent AS old_id FROM #relationtree
UNION
SELECT DISTINCT child AS old_id FROM #relationtree
) SQ
)
INSERT INTO dbo.Relations (Id, ParentId)
SELECT
CID.new_id,
PID.new_id
FROM
#relationtree RT
INNER JOIN CTE_MappedIDs PID ON PID.old_id = RT.parent
INNER JOIN CTE_MappedIDs CID ON CID.old_id = RT.parent
-- We need to also add the root node
UNION ALL
SELECT
NID.new_id,
NULL
FROM
#relationtree RT2
INNER JOIN CTE_MappedIDs NID ON NID.old_id = RT2.parent
WHERE
RT2.parent NOT IN (SELECT DISTINCT child FROM #relationtree)
SET IDENTITY_INSERT dbo.Relations OFF
我还没有测试过它,但是如果它不能像预期的那样工作,那么希望它能为您指明正确的方向。
发布于 2016-04-26 11:42:56
我知道您已经有了一个可行的答案,但我认为您可以使用延迟函数来检查上一行,前提是您有Server 2012或更高版本,您可以更简单地完成相同的任务(而不是Tom H的答案有任何问题)。
设置:
CREATE TABLE #relationtree (
Parent INT,
Child INT
)
CREATE TABLE #relations (
Id INT IDENTITY(1,1),
ParentId INT
)
INSERT INTO #relationtree (Parent, Child) VALUES(1,3), (3,5), (5,6), (5,9)
INSERT INTO #relations (ParentId) values(1), (3), (5)
解决方案:
DECLARE @offset INT = IDENT_CURRENT('#relations')
;WITH relationtreeids AS (
SELECT *,
ROW_NUMBER() OVER(ORDER BY Parent, Child) - 2 AS UnmodifiedParentId -- Simulate an identity field
FROM #relationtree
)
INSERT INTO #relations
-- The LAG window function allows you to inspect the previous row
SELECT CASE WHEN LAG(Parent) OVER(ORDER BY Parent) IS NULL
THEN NULL
WHEN LAG(Parent) OVER(ORDER BY Parent) = Parent
THEN UnmodifiedParentId + @offset ELSE UnmodifiedParentId + @offset + 1
END AS ParentId
FROM relationtreeids
输出:
Id ParentId
1 1
2 3
3 5
4 NULL
5 4
6 5
7 5
https://stackoverflow.com/questions/36872623
复制