我知道我可以通过多种方式实现这一点——这是一个纯粹的学术问题,看看是否可以在一条语句中做到这一点,以加深我对 SQL 的了解。
我们将一个旧的宽表拆分为两个较窄的表,一个父表和一个子表:
create table WorkTable
( ParentId int null
, ChildId int not null
, ParentField1 varchar(50) not null )
create table ParentTable
( Id int not null primary key identity
, Field1 varchar(50) not null )
create table ChildTable
( Id int not null primary key identity
, ParentId int not null foreign key references ParentTable ( Id ) )
WorkTable
包含原始表中的一堆记录 - 我们要用作子表中 ID 的该表中的 ID(通过identity_insert
),以及我们实际想要在父表中设置的该表中的字段。因此,对于 中的每一行WorkTable
,我们将在 中得到一行ParentTable
,在 中得到另一行ChildTable
。
现在我要填充ParentTable
,并获取其新插入记录的 ID,以便随后插入ChildTable
:
declare @IdsMap table
( ParentId int not null
, ChildId int not null )
merge ParentTable dst
using (
select ChildId
, ParentField1
from WorkTable
) src on 1 = 0
when not matched by target then
insert
( Field1 )
values
( src.ParentField1 )
output inserted.Id as [ParentId]
, src.ChildId -- can't do this with a standard INSERT...OUTPUT, hence the use of MERGE
into @IdsMap
;
update wkt
set wkt.ParentId = ids.ParentId
from WorkTable wkt
join
@IdsMap ids on ids.ChildId = wkt.ChildId
这有效,但它很丑陋。如果我可以将它简化为一条语句,我会更愿意,这样插入的 ID 可以ParentTable
直接更新回- 从而消除了对仅用于完成此更新的表 varWorktable
的需要。@IdsMap
我想我可以通过使用merge
嵌套 DML 来完成此操作:
update wkt
set wkt.ParentId = cte.ParentId
from WorkTable wkt
join
(
merge ParentTable dst
using (
select ChildId
, ParentField1
from WorkTable
) src on 1 = 0
when not matched by target then
insert
( Field1 )
values
( src.ParentField1 )
output inserted.Id as [ParentId]
, src.ChildId
) cte on cte.ChildId = wkt.ChildId
但 MSSQL 说不:
A nested INSERT, UPDATE, DELETE, or MERGE statement is not
allowed on either side of a JOIN or APPLY operator.
CTE 中的嵌套 DML 同样失败:
;with cte as
(
select *
from
(
merge ParentTable dst
using (
select ChildId
, ParentField1
from WorkTable
) src on 1 = 0
when not matched by target then
insert
( Field1 )
values
( src.ParentField1 )
output inserted.Id as [ParentId]
, src.ChildId
) _
)
update wkt
set wkt.ParentId = cte.ParentId
from WorkTable wkt
join
cte on cte.ChildId = wkt.ChildId
A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed in a SELECT
statement that is not the immediate source of rows for an INSERT statement.
有什么办法可以实现我想要的吗?