SQL Server : INSTEAD OF INSERT trigger & Identity column using view

后端 未结 2 1788
生来不讨喜
生来不讨喜 2021-01-22 04:54

I\'ve been banging my head against a wall for the better part of a week. I\'ve been studying SQL (T-SQL) for a few weeks now, and I\'ve hit a snag.

I\'m building a datab

相关标签:
2条回答
  • 2021-01-22 05:47

    Here is answer to your question "Getting Identity values to use as FK in an INSTEAD OF trigger"

    https://dba.stackexchange.com/questions/34258/getting-identity-values-to-use-as-fk-in-an-instead-of-trigger

    0 讨论(0)
  • 2021-01-22 05:52

    You can do this by using a table variable to hold the newly inserted IDs and all of the data that you're going to insert into the other tables. You need to do this because there's no way from just the first INSERTs data to join back to inserted in such a manner that you can match up the IDENTITY values with the rows that caused them to be generated.

    We also have to abuse MERGE since INSERT doesn't let you include anything other than the target table in its OUTPUT clause.

    I'm doing this on a toy example but hopefully you can see how to write it for your full table structures.

    First, some tables:

    create table dbo.Core (
        ID int IDENTITY(-71,3) not null,
        A varchar(10) not null,
        constraint PK_Core PRIMARY KEY (ID)
    )
    go
    create table dbo.Child1 (
        ID int IDENTITY(-42,19) not null,
        ParentID int not null,
        B varchar(10) not null,
        constraint PK_Child1 PRIMARY KEY (ID),
        constraint FK_Child1_Core FOREIGN KEY (ParentID) references Core(ID)
    )
    go
    create table dbo.Child2 (
        ID int IDENTITY(-42,19) not null,
        ParentID int not null,
        C varchar(10) not null,
        constraint PK_Child2 PRIMARY KEY (ID),
        constraint FK_Child2_Core FOREIGN KEY (ParentID) references Core(ID)
    )
    go
    

    And the view:

    create view dbo.Together
    with schemabinding
    as
        select
            c.ID,
            c.A,
            c1.B,
            c2.C
        from
            dbo.Core c
                inner join
            dbo.Child1 c1
                on
                    c.ID = c1.ParentID
                inner join
            dbo.Child2 c2
                on
                    c.ID = c2.ParentID
    go
    

    And finally the trigger:

    create trigger Together_T_I
    on dbo.Together
    instead of insert
    as
        set nocount on
        declare @tmp table (ID int not null, B varchar(10) not null, C varchar(10) not null);
    
        merge into dbo.Core c
        using inserted i
        on
            c.ID = i.ID
        when not matched then insert (A) values (i.A)
        output
            inserted.ID /* NB - This is the output clauses inserted,
                        not the trigger's inserted so this is now populated */
            ,i.B,
            i.C
        into @tmp;
    
        insert into dbo.Child1(ParentID,B)
        select ID,B
        from @tmp
    
        insert into dbo.Child2(ParentID,C)
        select ID,C
        from @tmp
    

    (And I would keep something like that comment in there since statements inside triggers that include OUTPUT clauses tend to be quite confusing since there are two inserted tables in play)

    (It's also noteworthy that it doesn't really matter what you put in the ON clause of the MERGE, so long as you're sure that it will fail to make a match. You may prefer to have, say, just 1=0 if you think it makes it clearer. I just went cute on the fact that the trigger's inserted.ID will be NULL)

    And now we do our insert:

    insert into dbo.Together(A,B,C) values ('aaa','bbb','ccc')
    go
    select * from dbo.Together
    

    And get the result:

    ID          A          B          C
    ----------- ---------- ---------- ----------
    -71         aaa        bbb        ccc
    
    0 讨论(0)
提交回复
热议问题