简体   繁体   中英

SQL Server : splitting a row into multiple rows from OUTPUT clause

I am trying to get a query that can help me achieve something similar to the image below:

输出结果集

The first table is the result of a SQL OUTPUT clause (both inserted and deleted). I would like to split these results into a new table (like the second one in the above image). So I want to have one row depicting the inserted records and the second row depicting the deleted records.

This is how my sample data was created:

select 
    inserted_ID = 1,
    inserted_name = 'Brian',
    inserted_phone = '123-456-7890',
    operation_type1 = 'inserted',
    deleted_id = 2,
    deleted_name = 'James',
    deleted_phone = '222-222-2222',
    operation_type2 = 'Deleted'
into 
    #tbltest

Try to organize your table structure something like (keep attention on [uid]):

create table [my_table]
(
     [id]       int
    ,[name]     nvarchar(256)
    ,[phone]    nvarchar(256)
); 

insert into [my_table] 
values (1, 'Brian', '123-456-7890');

create table [my_log]
(
     [inserted_id]      int
    ,[inserted_name]    nvarchar(256)
    ,[inserted_phone]   nvarchar(256)
    ,[deleted_id]       int
    ,[deleted_name]     nvarchar(256)
    ,[deleted_phone]    nvarchar(256)   
    ,[uid]              uniqueidentifier primary key    
);

And then this solves your problem:

update [my_table]
set [id]     = 2        
    ,[name]  = 'James'
    ,[phone] = '222-222-2222'
output
     [deleted].[id]
    ,[deleted].[name]
    ,[deleted].[phone]
    ,[inserted].[id]
    ,[inserted].[name]
    ,[inserted].[phone] 
    ,newid()
into [my_log]
(
     [inserted_id]
    ,[inserted_name]
    ,[inserted_phone]   
    ,[deleted_id]
    ,[deleted_name]
    ,[deleted_phone]    
    ,[uid]
);

select
     [id]       =   [id]
    ,[name]     =   [name]
    ,[phone]    =   [phone]
    ,[op_type]  =   CASE [op_type] WHEN 0 THEN 'Insert' ELSE 'Delete' END
from    
    ( 
        select 
             [id]       =   [inserted_id]
            ,[name]     =   [inserted_name]
            ,[phone]    =   [inserted_phone]
            ,[op_type]  =   0   --  insert
            ,[uid]      =   [uid]
        from 
            [my_log] 
        union
        select 
             [id]       =   [deleted_id]
            ,[name]     =   [deleted_name]
            ,[phone]    =   [deleted_phone]
            ,[op_type]  =   1   --  delete
            ,[uid]      =   [uid]
        from 
            [my_log]
    ) as [l]
order by 
     [l].[uid] 
    ,[l].[op_type]  ASC;
  1. Unless you are using the MERGE statement, you cannot both INSERT and DELETE in the same DML operation. The only time (outside of MERGE ) that you will have rows in both the inserted and deleted pseudo-tables is during an UPDATE operation, and in that case, the rows in both will refer to the same actual rows in the tables, just the before and after views of those rows. Meaning, you won't see values like are what is being shown in the question where Inserted_ID and Deleted_ID differ.

  2. If you are using MERGE , then you should already have the rows in the desired format since one row from the OUTPUT clause wouldn't represent multiple rows being affected. Meaning: OUTPUT already works are you are wanting it to, not as you are stating that it does.

Try to use OUTER / CROSS APPLY operator:

select ...
from #Output / @Output as o
cross apply (
    select o.insertedColA, o.insertedColB, 'I'
    -- where o.insertedID is not null
    union all
    select o.deletedColB, ..., 'D'
    -- where o.deletedID is not null
) as x(ColA, ColB, RowType)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM