Вы можете добавить отношения многие ко многим между таблицами Account (Id-PK, UserId-FK, Name, Description, ...) и Entry (Id-PK):
EntryAccount (EntryId & AccountId-PK, EntryAccountType)
где поле EntryAccountType может иметь одно из следующих значений: {S = отправитель, R = получатель, P = основной получатель, N = вторичный получатель}.
Операторы INSERT для таблицы EntryAccount будут:
--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) вы можете создать уникальный отфильтрованный индекс (SQL Server 2008) для таблицы EntryAccount: IUF_EntryAccount_EntryId_EntryAccountType (ключ> EntryId & EntryAccountType, фильтр> EntryAccountType IN ('S', 'P')). Также этот индекс хорош для оптимизации запросов.
Но этого индекса недостаточно, потому что вы можете иметь «несовместимые» бизнес-объекты Entry, подобные этим:
Entry(1001)
EntryAccoount(1001,...,'S') without EntryAccoount(1001,...,'R')
or
EntryAccoount(1001,...,'R') without EntryAccoount(1001,...,'S')
, etc.
Для исправления этой проблемы необходим триггер AFTER INSERT, UPDATE, DELETE в таблице EntryAccount:
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: я не проверял это решение.