不同表

时间:2018-04-25 13:28:53

标签: mysql database database-design

我有一个物业管理应用程序,内置了完整的会计系统。我有一个日记帐分录表,用于控制各种会计活动的所有过帐,例如:

发票
付款
票据
存款

在某些情况下,有必要将这些实体加入日记帐分录表,以按不同的属性和单位汇总会计分录。

我正在寻找最佳方法。我有几个选择:

1)在日记帐分录表上添加一个外键以链接到invoice_id,payment_id,bill_id,deposit_id,但是这些的大部分组合都是互斥的(即存款没有付款)所以我会有案例对于给定的日记帐分录,我将在那些不适用于该给定日记帐分录的外键中具有空值。

2)我可以创建一个外键,让我们称之为doc_id,另一列doc_type来表示文档类型(发票,付款,账单,存款等),并将doc_id和document_type_id组合起来引用a其中一个扩展表上的主键(即doc_id = 1& doc_type = Invoice,该组合将引用Invoice表上的主键)。

哪种方法更好或者我认为这一切都错了?

1 个答案:

答案 0 :(得分:0)

这听起来像是标准的基本实体/子实体模式。有一个表,我们称之为JournalEntries,它包含所有日记条目共有的属性:ID,条目类型,创建时间,创建者等等。

create table JournalEntries(
    ID       Int  auto_generating primary key,
    EType    char( 1 )  not null check( EType in( 'I', 'P', 'B', 'D' )) -- Invoice, Payment, etc.
    Amount   currency  not null,
    CreateDate  Date not null,
    ...,     -- other common attributes
    constraint UQ_JournalEntryType unique( ID, EType ) -- create anchor for FKs
);

请注意,ID是主键,因此是唯一的。因此,从域定义的角度来看,使ID和EType组合唯一的约束是多余的。它只是为外键定义一个锚。

这些FK将位于子实体表中 - 每个子实体一个表:发票,付款,账单和存款。请注意,如果在JournalEntries表中将条目定义为存款(EType =' D'),则只能在存款表中进行相应的条目。例如,您无法在付款表中错误地使用该ID。

让我们定义一个子实体表:

create table Invoices(
    ID    int   primary key, -- value generated by JournalEntries table
    IType char( 1 ) not null check( IType = 'I' ), -- Nothing but invoices
    ...,   -- Invoice-specific attributes
    constraint FK_InvoiceToEntry foreign key( ID, IType )
      references JournalEntries( ID, EType )
);

现在让我们创建一个活动,该活动始终有一个与之关联的发票,并且可能包含任意数量的其他条目。约束确保只能插入发票,ID值必须与定义为发票的JournalEntries条目匹配。

create table Activities(
  ID   int   auto_generating primary key,
  InvID int  not null,
  IType char( 1 ) check( IType = 'I' ),
  ...,   -- other data
  constraint FK_ActivityInvoice foreign key( InvID, Type )
);

可能有任意数量的附加条目,它们可能是任何条目类型,因此您需要一个交叉表:

create table ActivityEntries(
    ActID  int  not null,
    EntID  int  not null,
    DateEntered date not null,
    constraint FK_ActEntry_Activity foreign key( ActID )
      references Activities( ID ),
    constraint FK_ActEntry_JEntry foreign key( EntID )
      references JournalEntries( ID )
);

请注意"日记帐分录"是与其中一个子实体表关联的JournalEntries数据。因此,对任何日记帐分录的FK引用应该引用JournalEntries表,而不是任何子实体表,即使您知道它是什么类型的条目。因此,Activities行使用EType字段引用JournalEntries表作为额外的数据完整性工作,因为必须是发票。交集表包含任何类型的条目,因此其FK目标只是PK。

注意:出于说明目的,JournalEntries表中的类型指示符受到check语句的约束。在实际的数据库中,更好的设计是条目类型查找表。这保持了数据完整性,但设计更加灵活。 (另外,MySQL仍然(!)没有实现检查约束。)