我有一个看起来像这样的模型:
一个帐户有多个分支,每个帐户都会生成一个帐户。该模型是多余的,因为可以从事务上的BranchID推断出Account(标题上的AccountID)(一个语句将始终具有一个或多个事务)。
是否应从StatementHeader中删除AccountID,或者这种冗余级别是否正常?或者有更好的解决方案吗?
答案 0 :(得分:0)
如果您有StatementHeader,那么它应该具有AccountID以保持参照完整性。
但是,最好完全删除StatementHeader并将StatementDate移动到Statement记录中。这样可以使事情更清晰,并使模型更好地描述您想要的内容。
答案 1 :(得分:0)
由于陈述是历史性的,并且通常是只读的,因此数据有些冗余是正常的。我同意理查德哈里森的意见,并将[AccountID]和[StatementDate]都移到[Statement]表中;我的理由是你说一个帐户有很多分支,所以你将创建一个帐户的声明。
将所有这些数据存储在同一个地方会减少连接并加快报告速度,我认为这是该数据库的原因。
答案 2 :(得分:0)
有时,(真实的或感知的)冗余是业务规则的结果。在这种情况下,业务规则是:“发布到帐户的语句应仅包含属于该特定帐户的分支的事务。”
要强制执行该规则,您可以尝试提供一个数据库模式,使其无法违反该规则,或使用约束或触发器显式强制执行该规则。使用StatementHeader.AccountID似乎更容易。在Oracle中,您可以编写如下内容:
create or replace trigger statement_has_unique_account
before insert or update on Statement
referencing old as old new as new
for each row
declare
m integer;
n integer;
begin
select b.AccountID
into m
from Branch b
where b.ID = new.BranchID;
select s.AccountID
into n
from StatementHeader s
where s.ID = new.StatementID;
if m <> n then
raise_application_error(-1000, 'No way!');
end if;
end;
在StatementHeader中没有AccountID,您必须与共享相同StatementID的所有其他语句中的所有其他AccountID进行比较,从而产生更复杂的语句序列。
所以我会将AccountID作为StatementHeader中的外键保留,并使用触发器显式强制执行业务规则。