如何防止 INSTEAD OF 触发器触发,直到另一个 INSTEAD OF 触发器完成

问题描述 投票:0回答:1

我正在开发一个项目,其中两个应用程序读取/写入相同的表。这两个应用程序都不能更改。一个是用 Access 编写的,另一个是用 .NET 编写的,将替换 Access 应用程序,因此“拥有”表架构。

表架构是这样的:

检方:

CustomerID 
ProsecutionID

收费:

CustomerID 
ProsecutionID
ChargeID

收费详情:

CustomerID 
ChargeID

编辑:

CustomerID
已编辑以删除(PK)

Access 应用程序不会写入

CustomerID
,因此我在
INSTEAD OF
表上使用
Charges
触发器来从
CustomerID
查找
Prosecution

SET @CustomerID = (SELECT CustomerID 
                   FROM Prosecution 
                   WHERE ProsecutionID = ProsecutionID 
                   FROM INSERTED) 

ChargeDetail
表上,我有一个
INSTEAD OF
触发器,需要使用
 查找 
CustomerID

SET @CustomerID = (SELECT CustomerID  
                   FROM Charges 
                   WHERE ChargeID = ChargeID 
                   FROM INSERTED)

如果我首先更新并保存访问表单的费用部分,它就可以正常工作。问题在于,Access 中的

Charges
ChargeDetail
表单以一个表单的形式提交,并在两个区域中提交数据时,会导致
ChargeDetail
触发器首先触发,并因 PK 违规而失败,因为
Charges
尚未触发还没写完。

我的问题的长序言:

使

ChargeDetail
上的触发器“等待”其他触发器完成的最佳方法是什么?

我可以在触发器中放置一个

WHILE
循环来检查对另一个表的写入是否完成,但这听起来很危险。如果写入
WHILE
表因任何原因失败,我如何强制退出
Charges
循环?

触发器是否可以通过 SQL Server 确认另一个触发器的完成?

sql-server t-sql triggers
1个回答
0
投票

如果在收费详细信息的插入中,您注意到 CustomerID 丢失,您应该能够从您认为 CustomerID 不太可能达到的特定范围中分配一个数字,然后在费用中插入 ,用以下内容更新该数字实际数量。

这是一个例子:

代表表:

CREATE TABLE Q79238426.Prosecution (
    PK INT IDENTITY(1,1), 
    CustomerId INT NOT NULL,
    ProsecutionID INT NOT NULL,
    CONSTRAINT PK_Prosecution PRIMARY KEY CLUSTERED (PK, CustomerId)
)


CREATE TABLE Q79238426.Charges(
    PK INT IDENTITY(1,1),
    CustomerId INT NOT NULL,
    ProsecutionID INT NOT NULL,
    ChargeID INT NOT NULL,
    CONSTRAINT PK_Charges PRIMARY KEY CLUSTERED (PK, CustomerId)
)

CREATE TABLE Q79238426.ChargeDetail(
    PK INT IDENTITY(1,1),
    CustomerId INT NOT NULL,
    ChargeID INT NOT NULL,
    CONSTRAINT PK_ChargeDetail PRIMARY KEY CLUSTERED (PK, CustomerId)
)

提供已知范围内的数字的序列:

/* Sequence to provide known replacable "temp" CustomerIds*/
CREATE SEQUENCE Q79238426.TempCustomerId AS INT START WITH 1000000000 INCREMENT BY 1 MAXVALUE   1999999999  NO CYCLE

根据需要触发替换值:

CREATE OR ALTER TRIGGER  Q79238426.InsteadOf_Charges_Insert
ON Q79238426.Charges
INSTEAD OF INSERT
AS 
SET NOCOUNT ON

/* If a CustomerId was not passed, fill from Prosecution */
IF EXISTS( SELECT 1 FROM inserted WHERE CustomerId IS NULL) 
BEGIN
    
    /* Note: assuming an all or nothing on CustomerId */
    INSERT INTO Q79238426.Charges(CustomerId, ProsecutionID, ChargeID)
    SELECT p.CustomerID, i.ProsecutionID, i.ChargeId
    FROM inserted i
        JOIN Q79238426.Prosecution p on i.ProsecutionID = p.ProsecutionID
END     
ELSE 
    INSERT INTO Q79238426.Charges(CustomerId, ProsecutionID, ChargeID)
    SELECT CustomerId, ProsecutionID, ChargeID 
    FROM inserted

/* If there are any ChargeDetails with tempCustomerIds, update them based upon this insert */
UPDATE cd
SET CustomerId = i.CustomerId
FROM Q79238426.ChargeDetail cd
    JOIN inserted i ON i.ChargeId = cd.ChargeId AND cd.CustomerId >= 1000000000


GO


CREATE  TRIGGER  Q79238426.InsteadOf_ChargeDetail_Insert
ON Q79238426.ChargeDetail
INSTEAD OF INSERT
AS 
SET NOCOUNT ON

IF EXISTS( SELECT 1 FROM inserted WHERE CustomerId IS NULL) 
BEGIN
    /* Use Customer from Charge when available, if not supplied */
    SELECT ISNULL(i.CustomerId, c.CustomerId) CustomerId, i.ChargeId
    INTO #insert
    FROM inserted i
        LEFT JOIN Q79238426.Charges c on i.ChargeID = c.ChargeID

    /* Assign tempCustomerIds for any that still need it.  
        Note: is separate due to limitation is NEXT VALUE FOR; no case, coalesce, isnull allowed*/
    UPDATE #insert
    SET CustomerId = NEXT VALUE FOR Q79238426.TempCustomerId
    WHERE CustomerID IS NULL

    INSERT INTO Q79238426.ChargeDetail (CustomerId, ChargeId)
    SELECT CustomerId, ChargeId
    FROM #insert

END
ELSE
    INSERT INTO Q79238426.ChargeDetail (CustomerId, ChargeId)
    SELECT CustomerId, ChargeId FROM inserted

插入一些数据进行测试,注意顺序的差异:

INSERT INTO Q79238426.Prosecution(CustomerId, ProsecutionID) VALUES (10000, 10001)
INSERT INTO Q79238426.Charges(ProsecutionID, ChargeID) VALUES (10001, 10002)
INSERT INTO Q79238426.ChargeDetail(ChargeId) VALUES (10002)

INSERT INTO Q79238426.Prosecution(CustomerId, ProsecutionID) VALUES (20000, 20001)
INSERT INTO Q79238426.ChargeDetail(ChargeId) VALUES (20002)
INSERT INTO Q79238426.Charges(ProsecutionID, ChargeID) VALUES (20001, 20002)

确认输出:

SELECT * FROM Q79238426.Prosecution 
SELECT * FROM Q79238426.Charges 
SELECT * FROM Q79238426.ChargeDetail 

结果:

PK          CustomerId  ProsecutionID
----------- ----------- -------------
1           10000       10001
2           20000       20001

(2 rows affected)

PK          CustomerId  ProsecutionID ChargeID
----------- ----------- ------------- -----------
1           10000       10001         10002
2           20000       20001         20002

(2 rows affected)

PK          CustomerId  ChargeID
----------- ----------- -----------
1           10000       10002
2           20000       20002

(2 rows affected)
© www.soinside.com 2019 - 2024. All rights reserved.