您可以在 Account(Id-PK,UserId-FK,Name,Description,...) 和 Entry(Id-PK) 表之间添加多对多关系:
EntryAccount(EntryId & AccountId-PK,EntryAccountType)
其中 EntryAccountType 字段可以具有以下值之一 {S=Sender,R=Receiver, P=Primary receiver,N=secoNdary receiver}。
EntryAccount 表的 INSERT 语句将是:
--Basic
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'S')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'R')
--Parallel
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'S')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'R')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'R')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'R')
--Chained
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'S')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'P')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'N')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'N')
INSERT EntryAccount (EntryId,AccountId,EntryAccountType)
VALUES (...,...,'N')
然后,为了执行一些业务规则(一个发送者-S、一个主要接收者-P 和许多 [次要] 接收者-R/N),您可以在 EntryAccount 表上创建一个唯一的过滤索引(SQL Server 2008):IUF_EntryAccount_EntryId_EntryAccountType (key > EntryId & EntryAccountType, filter > EntryAccountType IN ('S','P'))。此外,此索引对于查询优化很有用。
但是,这个索引是不够的,因为你可以有这样的“不一致”的条目业务对象:
Entry(1001)
EntryAccoount(1001,...,'S') without EntryAccoount(1001,...,'R')
or
EntryAccoount(1001,...,'R') without EntryAccoount(1001,...,'S')
, etc.
要纠正这个问题,您需要在 EntryAccount 表上的 AFTER INSERT、UPDATE、DELETE 触发器:
CREATE TRIGGER ...
AFTER INSERT, UPDATE, DELETE
...
DECLARE @Results TABLE
(
EntryId INT PRIMARY KEY
,SendersCount INT NOT NULL DEFAULT O
,ReceiversCount INT NOT NULL DEFAULT O
,PrimaryReceiversCount INT NOT NULL DEFAULT O
,SecondaryReceiversCount INT NOT NULL DEFAULT O
);
INSERT @Results(EntryId)
SELECT EntryId
FROM inserted
UNION --no duplicates
SELECT EntryId
FROM deleted;
--Count senders
UPDATE @Results
SET SendersCount = q.Num
FROM @Results r
JOIN
(
SELECT ea.EntryId, COUNT(*) Num
FROM EntryAccount ea
JOIN @Results i ON ea.EntryId = i.EntryId
WHERE ea.EntryAccountType = 'S'
GROUP BY ea.EntryId
) q ON r.EntryId = q.EntryId;
-Count [standard-R] receivers
UPDATE @Results
SET ReceiversCount = q.Num
FROM @Results r
JOIN
(
SELECT ea.EntryId, COUNT(*) Num
FROM EntryAccount ea
JOIN @Results i ON ea.EntryId = i.EntryId
WHERE ea.EntryAccountType = 'R'
GROUP BY ea.EntryId
) q ON r.EntryId = q.EntryId;
--Count primary-P receivers
UPDATE @Results
SET PrimaryReceiversCount = q.Num
FROM @Results r
JOIN
(
SELECT ea.EntryId, COUNT(*) Num
FROM EntryAccount ea
JOIN @Results i ON ea.EntryId = i.EntryId
WHERE ea.EntryAccountType = 'P'
GROUP BY ea.EntryId
) q ON r.EntryId = q.EntryId;
--Count secondary-N receivers
UPDATE @Results
SET SecondaryReceiversCount = q.Num
FROM @Results r
JOIN
(
SELECT ea.EntryId, COUNT(*) Num
FROM EntryAccount ea
JOIN @Results i ON ea.EntryId = i.EntryId
WHERE ea.EntryAccountType = 'N'
GROUP BY ea.EntryId
) q ON r.EntryId = q.EntryId;
--Final validation
IF EXISTS
(
SELECT *
FROM @Results r
WHERE NOT(r.SendersCount=1 AND r.ReceiversCount>=1 AND r.PrimaryReceiver=0 AND r.SecondaryReceiversCount=0
OR r.SenderCount=1 AND r.ReceiversCount=0 AND r.PrimaryReceiver=1 AND r.SecondaryReceiversCount >=1
OR r.SenderCount=0 AND r.ReceiversCount=0 AND r.PrimaryReceiver=0 AND r.SecondaryReceiversCount=0
)
)
ROLLBACK;
如果您没有 SQL Server 2008 (R1/R2),则无法创建筛选索引,但只能依赖触发器。
PS:我没有测试过这个解决方案。