sql - INSTEAD OF INSERT 触发器和标识列使用 View

标签 sql sql-server database tsql

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

Microsoft Access 将用于与数据库交互(作为前端)。为了使事情更简单,我创建了一个 View ,将所有必需的表连接在一起,以便最终用户可以轻松查询信息。

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

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

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

成员 View :

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

最佳答案

您可以通过使用表变量来保存新插入的 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

和 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

最后是触发器:

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 子句的触发器中的语句往往非常困惑,因为有两个 插入 游戏中的表格)

(还值得注意的是,在 MERGEON 子句中放入什么并不重要,只要您确定它将 < em>fail 来匹配。你可能更喜欢,比方说,只是 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

关于sql - INSTEAD OF INSERT 触发器和标识列使用 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43060392/

相关文章:

sql-server - 更改 SQL Server 2008 R2 中的复制列。合并复制

database - 如何将数据库上传到 Heroku

php - MySQL使用另一个表中的值过滤一个表中的数据

xml - 从 XML 中提取范式

Mysql选择一个字段需要不同的条件

sql - 如何动态选择在存储过程中选择哪个表(具有相同架构)

sql-server - 带有存储过程和参数的 ASP 经典 SQL Server XML 格式

c# - dbo.Sometable 中的 dbo 是什么

MySQL Group By 多个列中的值相等

mysql - 使用声明的变量返回函数时出错