有3例
1) Basic
Sender ---> Receiver
2) Parallel
Sender ----> Receiver1
----> ReceiverN
3) Chained
Sender ----> Primary Receiver -----> Secondary Receiver1
-----> Secondary ReceiverN
对于1)Basic和2)Parallels,你可能会像这样设计你的表
Account
-Id (PK)
-UserId (FK)
-Name
-Description
-etc
Entry
-Id (PK)
-SenderAccountId (FK)
-ReceiverAccountId (FK)
现在您如何设计数据库以记录“链式”条目?
答案 0 :(得分:1)
您可以在帐户(Id-PK,UserId-FK,名称,描述,...)和条目(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 (键> 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.
要解决此问题,您需要在EntryAccount表上执行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:我还没有测试过这个解决方案。
答案 1 :(得分:0)
将一个parent_record_id添加到Entry表中。对于链中的第一步,它将为null。对于第二个,它将包含原始记录的ID。第三步,它将包含相关第二步的ID,依此类推。
我在评论中看到你说它最多可以有两个链接深度,所以你可以用另一种方法提出一种不同的解决方法,但这种方式是通用的,适用于很多场景,如果您的要求变为3级或更高级别的链接,则继续工作。
然后,您可以查找CONNECT BY SQL语法,以对此类数据结构执行有效的层次结构查询。