Quantcast
Channel: Active questions tagged cte - Database Administrators Stack Exchange
Viewing all articles
Browse latest Browse all 207

Is it possible to update an existing table in a single statement, using the output of a MERGE statement?

$
0
0

I know I can achieve this in many ways - this is a purely academic question to see if it's possible to do this in a single statement, in order to further my knowledge of SQL.

We're splitting an old, wide table into two narrower tables, a parent and a child:

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 contains a bunch of records from the original table - the ID from that table which we want to use as the ID in the child table (via identity_insert), and a field from that table that we actually want to set on the parent. For every row in WorkTable, therefore, we'll get 1 row in ParentTable and another in ChildTable.

Now I'm going to populate ParentTable, and also get the IDs of its newly-inserted records for the subsequent insert into ChildTable:

declare @IdsMap table      ( ParentId int not null      , ChildId  int not null )merge ParentTable dstusing (select ChildId     , ParentField1  from WorkTable) src on 1 = 0when not matched by target theninsert     ( 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

This works, but it's ugly. I'd much prefer if I could simplify it into one statement, whereby the inserted IDs from ParentTable are updated directly back into Worktable - thus removing the need for the @IdsMap table var that exists solely to accomplish this update.

I thought I might be able to accomplish this by using the merge as nested DML:

update wkt   set wkt.ParentId = cte.ParentId  from WorkTable wkt           join(merge ParentTable dstusing (select ChildId     , ParentField1  from WorkTable) src on 1 = 0when not matched by target theninsert     ( Field1 )values     ( src.ParentField1 )output inserted.Id as [ParentId]     , src.ChildId) cte on cte.ChildId = wkt.ChildId

but MSSQL says no:

A nested INSERT, UPDATE, DELETE, or MERGE statement is notallowed on either side of a JOIN or APPLY operator.

Nested DML inside a CTE similarly fails:

;with cte as(select *  from(merge ParentTable dstusing (select ChildId     , ParentField1  from WorkTable) src on 1 = 0when not matched by target theninsert     ( 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 SELECTstatement that is not the immediate source of rows for an INSERT statement.

Is there any way to achieve what I'm looking for?


Viewing all articles
Browse latest Browse all 207

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>