我试图对一组规范不足的分层表中的一系列参照行执行稍微复杂的复制操作。不幸的是,这些表使用代理键,但是在层次结构中有一些实例,其中某些表具有代理键但在表中没有有效的唯一性属性。因此,当我在每个分层表中插入我复制的行时,有些情况下我无法避免重复记录,因为我无法正确区分有效重复的行。可悲的是,我无法改变这个数据库的结构。
我使用的技术是基于SELECT语句的结果进行INSERT,其中select中的每一行将形成源实体层次结构的行连接在一起;从此连接结果中,复制的内容将被捕获并插入到表示目标层次结构的行中。在join语句中,使用代理键ID。例如:
INSERT INTO [PersonTable]
SELECT [sourcePerson].[Content], [destParent].[Id]
FROM [GrandParentTable] [sourceGrandParent]
JOIN [ParentTable] [sourceParent] ON [sourceParent].[GrandParentId] = [sourceGrandParent].[Id]
JOIN [PersonTable] [sourcePerson] ON [sourcePerson].[ParentId] = [sourceParent].[Id]
JOIN [GrandParentTable] [destGrandParent] ON [destGrandParent].[Name] = 'CopyTo'
JOIN [ParentTable] [destParent] ON [destParent].[GrandParentId] = [destGrandParent].[Id]
WHERE [sourceGrandParent].[Name] = 'CopyFrom'
我的问题是这个假设的表[PersonTable]没有足够的列或约束来唯一地标识其中的行,所以如果我想随后从另一个表[ChildTable]复制行,我会得到重复的行执行后续查询:
INSERT INTO [ChildTable]
SELECT [sourceChild].[Content], [destPerson].[Id]
FROM [GrandParentTable] [sourceGrandParent]
JOIN [ParentTable] [sourceParent] ON [sourceParent].[GrandParentId] = [sourceGrandParent].[Id]
JOIN [PersonTable] [sourcePerson] ON [sourcePerson].[ParentId] = [sourceParent].[Id]
JOIN [ChildTable] [sourceChild] ON [sourceChild].[PersonId] = [sourcePerson].[Id]
JOIN [GrandParentTable] [destGrandParent] ON [destGrandParent].[Name] = 'CopyTo'
JOIN [ParentTable] [destParent] ON [destParent].[GrandParentId] = [destGrandParent].[Id]
JOIN [PersonTable] [destPerson] ON [destPerson].[ParentId] = [destParent].[Id]
WHERE [sourceGrandParent].[Name] = 'CopyFrom'
我希望解决这个问题的一种方法是以某种方式将复制的行ID与源ID相关联,并将它们存储在可替换这些连接的临时表中。我想为此使用OUTPUT子句,以便我可以获取插入的行的[Id]值,但即使你应该能够从连接的表中输出任何内容似乎也是明智的,这不是&#39在这种情况下。
假设下一个示例已经存在一个我们已填充有效ID对的表:
CREATE TABLE #tempParentIds
(
[destParentId] int
[sourceParentId] int
)
我们尝试使用以下语句填充层次结构中的下一级:
CREATE TABLE #tempPersonIds
(
[destPersonId] int
[sourcePersonId] int
)
INSERT INTO [PersonTable] ([Content], [ParentId])
OUTPUT INSERTED.[Id], [sourcePerson].[Id] INTO #tempPersonIds
SELECT [sourcePerson].[Content], [destPerson].[ParentId]
FROM #tempParentIds [tempParent]
JOIN [PersonTable] [sourcePerson] ON [sourcePerson].[ParentID] = [tempParent].[sourceParentId]
JOIN [PersonTable] [destPerson] ON [destPerson].[ParentId] = [tempParent].[destParentId]
但是,此语句不会执行,因为[sourcePerson]在OUTPUT子句中不可访问,因此我们无法跟踪从其复制的源行和目标行。
除了插入行的列外部的信息之外,还有办法从插入的行中获取信息吗?如果这是可能的,我很想知道如何,但如果我根据我的问题描述以错误的方式解决这个问题,请随时让我直截了当。
答案 0 :(得分:1)
这是诀窍:
INSERT语句不能输出不在INSERTED中的源字段,而是MERGE语句可以。
merge into dbo.PersonTable as target
using
(
SELECT
sourcePerson.ID,
sourcePerson.Content,
destPerson.ParentId,
FROM
#tempParentIds tempParent
JOIN PersonTable sourcePerson ON sourcePerson.ParentID = tempParent.sourceParentId
JOIN PersonTable destPerson ON destPerson.ParentId = tempParent.destParentId
)
as source on source.ID * (-1) = target.ID
when not matched by target then
insert (Content, ParentId)
values (source.Content, source.ParentId)
output inserted.ID, source.ID
into #tempPersonIds ( destPersonId, sourcePersonId);