Внешний ключ для нескольких первичных ключей в разных таблицах - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть приложение для управления имуществом со встроенной системой учета.У меня есть таблица записей журнала, которая контролирует все проводки для различных учетных операций, таких как:

Счета
Платежи
Счета
Депозиты

В некоторых случаях необходимо присоединитьсяэти объекты в таблицу записей журнала для агрегирования учетных записей по различным свойствам и единицам.

Я ищу лучший способ сделать это.У меня есть несколько вариантов:

1) Добавить внешний ключ в таблицу записей журнала, чтобы связать его с invoice_id, payment_id, bill_id, deposit_id, однако большинство их комбинаций будут взаимоисключающими (т.е. депозит не будет иметьплатеж), поэтому у меня будут случаи, когда для данной записи журнала у меня будут нулевые значения в тех внешних ключах, которые не применяются к данной записи журнала.

2) Я мог бы создать один внешний ключ, давайте назовемэто doc_id и другой столбец doc_type, чтобы указать тип документа (Счет-фактура, Платеж, Счет, Депозит и т. д.) и иметь комбинацию doc_id и document_type_id для ссылки на первичный ключ в одной из таблиц расширений (т.е. doc_id = 1 & doc_type).= Счет, по которому эта комбинация будет ссылаться на первичный ключ в таблице счетов-фактур).

Какой лучший способ сделать это, или я думаю, что все это неправильно?

1 Ответ

0 голосов
/ 26 апреля 2018

Это звучит как стандартный шаблон базового объекта / дополнительного объекта.Есть одна таблица, назовем ее 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 все еще (!) Не реализует проверочные ограничения.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...