SQL Server:INSTEAD OF INSERT触发器&使用视图的标识列

时间:2017-03-28 03:55:32

标签: sql sql-server database tsql

在一周的大部分时间里,我一直在撞墙。我已经研究了SQL(T-SQL)几周了,我遇到了麻烦。

我正在构建一个存储公司客户数据的数据库。 DB中的表是规范化的,因此我有多个表使用外键约束链接在一起。

Microsoft Access将用于与数据库连接(作为前端)。为了简化操作,我创建了一个视图,将所有必需的表连接在一起,以便最终用户可以轻松查询信息。

我遇到的问题涉及将信息插入此视图。根据我的理解,由于我在视图中有多个表,因此我必须使用带有INSTEAD OF INSERT语句的触发器。我创造了触发器;但是,我不确定如何使用表中的ID列(这些列充当键)。

我有一个MemberBasicInformation表,其中包含客户端的DOB,名称,性别等及其MemberID。此ID是表中的IDENTITY列,因此会自动生成。我遇到的问题是因为身份是自动生成的,我无法获取插入MemberBasicInformation表后生成的身份值并将其插入到其他相关表中。当我尝试这样做时,我最终会违反外键约束。

我尝试使用@@IdentityScope_Identity()无济于事。我已经列出了我的观点和触发器,让您了解事情是如何设置的。如果有人能指出我正确的方向,我将不胜感激。我真的很茫然。

MEMBER查看:

CREATE VIEW [dbo].[Member]
AS
    SELECT        
        dbo.MemberBasic.MemberId, dbo.MemberBasic.FirstName, 
        dbo.MemberBasic.MiddleInitial, dbo.MemberBasic.LastName, 
        dbo.MemberBasic.FullName, dbo.MemberBasic.DateOfBirth, 
        dbo.Gender.Name AS Gender, dbo.MemberBasic.Address, 
        dbo.MemberBasic.Address2, dbo.MemberBasic.City, 
        dbo.MemberBasic.State, dbo.MemberBasic.ZipCode, 
        dbo.MemberBasic.PhoneNumber, 
        dbo.MemberBasic.SocialSecurityNumber, 
        dbo.MemberBasic.DriversLicense, 
        dbo.MemberBasic.EmployerIdentificationNumber, 
        dbo.MemberBasic.Notes, 
        dbo.FieldRep.Name AS FieldRepName, 
        dbo.MemberDetail.DateAssigned AS FieldRepDateAssigned, 
        dbo.MemberDetail.CPReceivedOn, dbo.MemberDetail.CredentialedOn, 
        dbo.MemberEligibility.IsActive, dbo.ICO.Name AS ICO, 
        dbo.MemberEligibility.StartDate AS EligibilityStartDate, 
        dbo.MemberEligibility.EndDate AS EligibilityEndDate, 
        dbo.MemberWorkerCompDetail.ExpirationDate AS WorkerCompExpirationDate, 
        dbo.MemberWorkerCompDetail.AuditDate AS WorkerCompAuditDate, 
        dbo.WorkerCompTier.Name AS WorkerCompTier, 
        dbo.MemberAttachment.AttachmentId, 
        dbo.MemberAttachment.Data AS AttachmentData
    FROM            
        dbo.MemberAttachment 
    INNER JOIN
        dbo.MemberBasic ON dbo.MemberAttachment.MemberId = dbo.MemberBasic.MemberId 
    INNER JOIN
        dbo.MemberCaregiverAssignment ON dbo.MemberAttachment.MemberId = dbo.MemberCaregiverAssignment.MemberId 
    INNER JOIN
        dbo.MemberDetail ON dbo.MemberBasic.MemberId = dbo.MemberDetail.MemberId 
    INNER JOIN
        dbo.MemberEligibility ON dbo.MemberAttachment.MemberId = dbo.MemberEligibility.MemberId 
    INNER JOIN
        dbo.MemberWorkerCompDetail ON dbo.MemberAttachment.MemberId = dbo.MemberWorkerCompDetail.MemberId 
    INNER JOIN
        dbo.Gender ON dbo.MemberBasic.GenderId = dbo.Gender.GenderId 
    INNER JOIN
        dbo.FieldRep ON dbo.MemberDetail.FieldRepId = dbo.FieldRep.FieldRepId 
    INNER JOIN
        dbo.ICO ON dbo.MemberEligibility.ICOId = dbo.ICO.ICOId 
    INNER JOIN
        dbo.WorkerCompTier ON dbo.MemberWorkerCompDetail.TierId = dbo.WorkerCompTier.TierId
GO

MEMBER触发器:

ALTER TRIGGER [dbo].[InsertNewMember] 
ON [dbo].[Member] 
INSTEAD OF INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    INSERT INTO MemberBasic (FirstName, MiddleInitial, LastName, GenderId, DateOfBirth, Address, Address2, City, State, ZipCode, PhoneNumber, SocialSecurityNumber, DriversLicense, EmployerIdentificationNumber, Notes)
        SELECT 
            FirstName, MiddleInitial, LastName, GenderId, DateOfBirth, 
            Address, Address2, City, State, ZipCode, PhoneNumber, 
            SocialSecurityNumber, DriversLicense, 
            EmployerIdentificationNumber, Notes 
        FROM 
            inserted
        INNER JOIN
            Gender ON Gender.Name = Gender; 

    INSERT INTO MemberDetail (MemberId, FieldRepId, DateAssigned, CPReceivedOn, CredentialedOn)
        SELECT 
            MemberId, FieldRep.FieldRepId, FieldRepDateAssigned, 
            CPReceivedOn, CredentialedOn
        FROM 
            inserted
        INNER JOIN
            FieldRep ON FieldRep.Name = FieldRepName;

    INSERT INTO MemberEligibility (MemberId, ICOId, StartDate, EndDate)
        SELECT 
            MemberId, ICOId, EligibilityStartDate, EligibilityEndDate 
        FROM 
            inserted
        INNER JOIN
            ICO ON ICO.Name = ICO;

    INSERT INTO MemberWorkerCompDetail (MemberId, AuditDate, ExpirationDate, TierId)
        SELECT 
            MemberId, WorkerCompAuditDate, WorkerCompExpirationDate, TierId
        FROM 
            inserted
        INNER JOIN
            WorkerCompTier ON WorkerCompTier.Name = WorkerCompTier;

    INSERT INTO MemberAttachment (MemberId, Data)
        SELECT MemberId, AttachmentData
        FROM Member
END

2 个答案:

答案 0 :(得分:1)

您可以使用表变量来保存新插入的ID 您要插入其他表的所有数据。您需要执行此操作,因为只有第一个INSERT数据才能以这样的方式加入inserted,以便您可以将IDENTITY值与导致它们生成的行。

我们还必须滥用MERGE,因为INSERT不允许您在其OUTPUT子句中包含目标表以外的任何内容。

我是在一个玩具示例中做到这一点,但希望你能看到如何为全表结构编写它。

首先,一些表格:

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

观点:

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

最后是触发器:

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

(我会在那里保留类似的评论,因为包含OUTPUT子句的触发器内的语句往往很混乱,因为有两个 inserted表在起作用)

(同样值得注意的是,只要您确定它ON MERGE条款中的内容并不重要将失败进行匹配。如果您认为它更清晰,您可能更愿意拥有1=0。我只是对触发器的事实感到很可爱inserted.ID将为NULL

现在我们进行插入:

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

得到结果:

ID          A          B          C
----------- ---------- ---------- ----------
-71         aaa        bbb        ccc

答案 1 :(得分:0)

以下是您的问题“在INSTEAD OF触发器中将身份值用作FK”的答案

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