我正在开发一个项目,其中两个应用程序读取/写入相同的表。这两个应用程序都不能更改。一个是用 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 确认另一个触发器的完成?
如果在收费详细信息的插入中,您注意到 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)