Это звучит как стандартный шаблон базового объекта / дополнительного объекта.Есть одна таблица, назовем ее 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'), соответствующая запись может быть сделана только в таблице Депозиты.Например, вы не можете ошибочно использовать этот идентификатор, скажем, в таблице платежей.
Давайте определим одну из таблиц субстанций:
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 )
);
Теперь давайте создадим действие, которое всегдаимеет один Счет, связанный с ним и может иметь любое количество других записей.Ограничения гарантируют, что могут быть вставлены только счета-фактуры, а значение идентификатора должно соответствовать записи 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, а не на любую из таблиц subentity, даже если вы знаете, что это за запись.Таким образом, строки «Деятельности» ссылаются на таблицу JournalEntries с использованием поля EType в качестве дополнительного усилия по обеспечению целостности данных, поскольку должно быть счетом.Таблица пересечений содержит записи любого типа, поэтому ее целью FK является просто PK.
Примечание: в целях иллюстрации индикатор типа в таблице JournalEntries был ограничен оператором check.В реальной базе данных гораздо лучшим дизайном была бы таблица поиска типов записей.Это поддерживает целостность данных, но гораздо более гибкий дизайн.(Плюс тот факт, что MySQL все еще (!) Не реализует проверочные ограничения.)