这个有点棘手。
但下面是一个可行的解决方案。
具有输出值和原始值的“合并”(将两种类型的值都放入#Holder 表中)是诀窍。
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Menu' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Menu]
END
GO
CREATE TABLE [dbo].[Menu](
[MenuId] [bigint] IDENTITY(1,1) NOT NULL,
[MenuName] [nvarchar](50) NULL,
[ParentId] [bigint] NULL,
[VersionNumber] [bigint] NULL,
CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED
(
[MenuId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Menu] ON
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (1, N'Customer', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (2, N'Home', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (3, N'About', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (4, N'Add Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (5, N'Administration', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (6, N'Edit Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (7, N'Tenant', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (8, N'Manage Contact', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (9, N'Users', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (10, N'Customer List', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (11, N'Contact', NULL, 1)
SET IDENTITY_INSERT [dbo].[Menu] OFF
select * from [dbo].[Menu]
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
/* The "mapping values" holder/tracking table */
CREATE TABLE #Holder
(
--SurrogateKeyIDENTITY int not null IDENTITY (1,1) ,
OriginalMenuId [bigint] NULL,
OriginalParentId [bigint] NULL,
NewMenuSurrogateKey int null ,
NewParentIdSurrogateKey int null
)
/* This is the key trick. You need to do the INSERT and keep track of old and new surrogate keys. The MERGE trick is the only way to get values into the #holder...combining "output" values and original values */
MERGE INTO [dbo].[Menu] pc
USING [dbo].[Menu] AS sourceTable
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT([MenuName], [VersionNumber])
Values([MenuName] , [VersionNumber] + 1 ) /* Here is your "plus one" for the Version */
Output sourceTable.MenuId , sourceTable.ParentId , inserted.MenuID INTO
#Holder (OriginalMenuId , [OriginalParentId] , NewMenuSurrogateKey );
Select 'Before the NewParentIdSurrogateKey is Updated Values' as Lab1 , * from #Holder
Update holderAsParent Set NewParentIdSurrogateKey = holderAsChild.NewMenuSurrogateKey
/* You can comment out the previous update and uncomment the next select statement to see what the update is trying to do */
/* Select 'Here1' as Lab1 , holderAsChild.NewMenuSurrogateKey, '----' as Sep1, holderAsChild.* , '----' as Sep2 , holderAsParent.* */
from
#Holder holderAsChild
join #Holder holderAsParent on holderAsChild.OriginalMenuId = holderAsParent.OriginalParentId
Select 'ShouldHaveAllTheMappingValuesInTheHolderNow' as Lab1 , * from #Holder
Update dbo.Menu Set [ParentId] = holder.NewParentIdSurrogateKey
from
dbo.Menu men join #Holder holder on men.MenuId = holder.NewMenuSurrogateKey
where holder.NewParentIdSurrogateKey iS NOT NULL
Select 'Final Results' as Lab1 , * from dbo.Menu
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
/* Sanity Check */
Select COALESCE(parent.MenuName + ' -- ', '') + child.MenuName as ParentThenChildMenuName, child.VersionNumber
from
[dbo].[Menu] child
left join
[dbo].[Menu] parent
on child.ParentId = parent.MenuId
where child.VersionNumber = 1
order by parent.MenuName , child.MenuName
Select COALESCE(parent.MenuName + ' -- ', '') + child.MenuName as ParentThenChildMenuName, child.VersionNumber
from
[dbo].[Menu] child
left join
[dbo].[Menu] parent
on child.ParentId = parent.MenuId
where child.VersionNumber = 2
order by parent.MenuName , child.MenuName
以下是参考。这是导致在这种特殊情况下在“from_table_name”中使用 MERGE 的小提示。
http://msdn.microsoft.com/en-us/library/ms177564.aspx
“来自_table_name”
是列前缀,用于指定包含在 DELETE、UPDATE 或 MERGE 语句的 FROM 子句中的表,用于指定要更新或删除的行。