SQL Server:而不是插入触发器&;使用视图的标识列

SQL Server:而不是插入触发器&;使用视图的标识列,sql,sql-server,database,tsql,Sql,Sql Server,Database,Tsql,一周的大部分时间里,我都在用头撞墙。我已经学习SQL(T-SQL)几个星期了,但遇到了一个障碍 我正在建立一个数据库来存储公司的客户数据。数据库中的表是规范化的,因此我有多个表,它们使用外键约束链接在一起 Microsoft Access将用于连接数据库(作为前端)。为了简化操作,我创建了一个视图,将所有必需的表连接在一起,以便最终用户可以轻松地查询信息 我遇到的问题是在这个视图中插入信息。根据我的理解,因为我的视图中有多个表,所以我必须使用带有的触发器,而不是INSERT语句。我创造了触发器;

一周的大部分时间里,我都在用头撞墙。我已经学习SQL(T-SQL)几个星期了,但遇到了一个障碍

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

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

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

我有一个
MemberBasicInformation
表,其中包含客户的DOB、姓名、性别等及其MemberID。此
ID
是表中的
IDENTITY
列,因此它是自动生成的。我遇到的问题是,由于标识是自动生成的,因此我无法获取插入
MemberBasicInformation
表后生成的标识值,并将其插入其他相关表。当我尝试这样做时,我最终会遇到一个外键约束冲突

我尝试过使用
@@Identity
Scope\u Identity()
但没有效果。我列出了我的观点和触发点,让你了解事情是如何设置的。如果有人能给我指出正确的方向,我将不胜感激。我真是不知所措

成员
查看:

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
成员
触发器:

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

下面是对您的问题“获取标识值以用作INSTEAD OF触发器中的FK”的回答


您可以使用一个表变量来保存新插入的ID以及要插入到其他表中的所有数据。您需要这样做,因为无法从第一个
INSERT
s数据连接回
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
子句的语句往往非常混乱,因为有两个
插入的
表在起作用)

(同样值得注意的是,你在
合并
ON
子句中放什么其实并不重要,只要你确定它将无法匹配。如果你认为它更清楚的话,你可能更愿意,比如说,
1=0
。我只是因为触发器的
插入了.ID
而变得可爱de>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

使用
@@IDENTITY
SCOPE\u IDENTITY()
时会发生什么情况?是否尝试使用
IDENT\u CURRENT('tableName')
?你真的确定可以在视图中插入新记录吗?据我所知,视图只是一个视图,它不能插入新行,也不能更新值……这都是因为视图记录来自其他表,而不是视图本身。你为什么不能直接插入基表?@reds-可更新视图并不少见。简单的视图允许自动更新。更复杂的视图需要触发器。
MemberBasic
表中是否有什么东西可以唯一地标识除
MemberId
之外的成员?可能是
employeeIdentificationNumber
?哇!太好了!非常感谢您为我分析了这个问题。现在只有一个了新插入的数据在从视图中查询时不会显示的小问题,但我会解决这个问题。