Как смоделировать это отношение множественного наследования с RDBMS? - PullRequest
2 голосов
/ 19 июня 2009

Я смотрю на эту модель данных, которую я придумала и не чувствую себя комфортно. Я изменил имена сущностей, так что (надеюсь) имеет больше смысла. В любом случае, как бы вы смоделировали следующее?

У меня есть 3 объекта. Государственный клиент, Частный клиент, Государственный клиент. Частные и государственные заказчики являются корпоративными клиентами. Корпоративные и государственные клиенты - это счета. Все учетные записи используют одно и то же пространство ключей (поэтому, если у PrivateCustomer есть PK, равный 1, у Public или GovernmentCustomer не должно быть PK, равного 1). Корпоративные клиенты имеют некоторые отношения 1: M, которых нет у государственных клиентов. У PublicCustomers есть некоторые отношения 1: M, которых у PrivateCustomers нет.

Наследование:

Account
  CorporateCustomer
    PrivateCustomer
    PublicCustomer
  GovernmentCustomer

Сейчас у моей модели 5 таблиц. Таблица «Account» является корнем этой иерархии, где PK каждой дочерней таблицы является FK для PK ее родителя. Таким образом, все таблицы имеют одинаковый PK.

Так что да, как бы вы смоделировали это? Я надеюсь, что здесь что-то пошло не так:).

EDIT:

Также: - Я бы хотел, чтобы БД заботилась о целостности ссылок, а не о приложении. - Корпоративный клиент не может существовать, не будучи частным или государственным клиентом. Его аннотация.

Ответы [ 6 ]

1 голос
/ 29 апреля 2011

Прежде чем вы решите поместить все классы в одну таблицу, я бы посмотрел на отношения , в которые они вовлечены, а не на атрибуты. Обязательно оставлять пустыми определенные поля, если тип записи «X», но невероятно громоздко пытаться иметь отношения, которые применяются только к определенным записям в таблице.

Если отношения классов с другими сущностями точно такие же, то вы можете сложить их все в одну таблицу без каких-либо реальных недостатков.

1 голос
/ 19 июня 2009

В одну сторону может быть:

ACCOUNTS -> ACCOUNT_CUSTOMERS <- CUSTOMERS

Сделать так, чтобы CUSTOMERS имел столбец CUSTOMER_TYPE, который имеет тип Corporate (C), Private (P), Public (Z), Government (G). Поскольку все публичные и частные клиенты также являются корпоративными, если вам нужно было привлечь всех корпоративных клиентов, вы можете сделать что-то вроде:

SELECT *
  FROM ACCOUNTS
     , ACCOUNT_CUSTOMERS
     , CUSTOMERS
 WHERE ACCOUNTS.ID = ACCOUNT_CUSTOMERS.ACCT_ID
   AND CUSTOMERS.ID = ACCOUNT_CUSTOMERS.CUST_ID
   AND CUSTOMERS.CUSTOMER_TYPE in ('C','P','Z')

Я использовал синтаксис ORACLE, но я думаю, вы поняли.

In response to your edit:

Похоже, у вас есть только два типа клиентов. Корпоративные и государственные. Это еще проще тогда. Я бы использовал логический индикатор на CUSTOMERS, называемый PUBLIC_IND, который, когда false, является закрытым, или другой тип, например ENTITY_TYPE, который может быть Private (P), Public (Z) или None (N). Тогда, если вы хотите получить всех публичных корпоративных клиентов:

SELECT *
      FROM ACCOUNTS
         , ACCOUNT_CUSTOMERS
         , CUSTOMERS
     WHERE ACCOUNTS.ID = ACCOUNT_CUSTOMERS.ACCT_ID
       AND CUSTOMERS.ID = ACCOUNT_CUSTOMERS.CUST_ID
       AND CUSTOMERS.CUSTOMER_TYPE in ('C')
       AND CUSTOMERS.ENTITY_TYPE = 'Z'
0 голосов
/ 20 июля 2014

Я знаю, что этот вопрос очень старый, но так как на него еще не принято ответа, у меня есть пара идей.

Одна из возможностей - использовать функции ORDBMS - другими словами, использовать наследование таблиц. В PostgreSQL вы можете смоделировать это так:

(см. Документацию о наследовании PostgresSQL http://www.postgresql.org/docs/9.3/static/ddl-inherit.html)

CREATE TABLE account
(
   account_id INT,
   PRIMARY KEY(account_id)
);

CREATE TABLE corporate_customer
(
   company_name VARCHAR(32),
   country_code CHAR(2),
   PRIMARY KEY(company_name)
) INHERITS(account);

CREATE TABLE private_corp_customer
(
   private_comp_id INT,
   company_owner VARCHAR(32),
   PRIMARY KEY(private_comp_int)
) INHERITS(corporate_customer);

CREATE TABLE public_corp_customer
(
   stock_ticker VARCHAR(6),
   PRIMARY KEY(stock_ticker)
) INHERITS(corporate_customer);

CREATE TABLE government_customer
(
   dept_nbr INT,
   country CHAR(2),
   PRIMARY KEY(dept_nbr)
) INHERITS(account);

Различные поставщики СУБД будут реализовывать это по-разному. В PostgresSQL есть несколько важных предостережений, описанных здесь:

http://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-3-table.html

В частности, обратите внимание на то, что первичные и внешние ключи не наследуются.

Если вам не нравятся ограничения вашей СУБД или вы используете СУБД, которая не имеет объектно-реляционных функций, тогда другой вариант - использовать альтернативу, предложенную в статье выше, и использовать вторичные ключи. Это было бы смоделировано так:

CREATE TABLE account
(
   account_id INT,
   account_type INT NOT NULL,
   PRIMARY KEY(account_id),
   UNIQUE (account_id, account_type)
);

CREATE TABLE corporate_customer
(
   account_id INT,
   account_type INT NOT NULL CHECK(account_type IN (1,2)),
   company_name VARCHAR(32),
   country_code CHAR(2),
   PRIMARY KEY(account_id, account_type),
   FOREIGN KEY(account_id, account_type) REFERENCES account(account_id, account_type),
   UNIQUE(account_id, account_type, company_name)
);

CREATE TABLE private_corp_customer
(
   account_id INT,
   account_type INT NOT NULL CHECK(account_type = 1),
   company_name VARCHAR(32),
   company_owner VARCHAR(32),
   PRIMARY KEY(account_id, account_type, company_name),
   FOREIGN KEY(account_id, account_type, company_name) REFERENCES corporate_customer (account_id, account_type, company_name)
);

CREATE TABLE public_corp_customer
(
   account_id INT,
   account_type INT NOT NULL CHECK (account_type = 2),
   company_name VARCHAR(32),
   stock_ticker CHAR(6),
   PRIMARY KEY(account_id, account_type, company_name),
   FOREIGN KEY(account_id, account_type, company_name) 
   REFERENCES corporate_customer (account_id, account_type, company_name)
) INHERITS(corporate_customer);

CREATE TABLE government_customer
(
   account_id INT,
   account_type INT NOT NULL CHECK(account_type = 3),
   dept_nbr INT,
   country_code CHAR(2),
   PRIMARY KEY(account_id, account_type),
   FOREIGN KEY(account_id, account_type) REFERENCES account(account_id, account_type),
   UNIQUE(account_id, account_type, dept_nbr)
 );

Приведенный выше дизайн также имеет некоторые важные ограничения (которые также описаны в статье выше). С одной стороны, хотя не должно быть возможности иметь учетную запись, которая не является частным, государственным или государственным клиентом, это возможно сделать; Вы можете иметь только учетные записи, корпоративные учетные записи, которые не являются ни общедоступными, ни частными ... это становится кошмаром. Ограничения CHECK также могут снизить производительность, и вы заметите, что в дочерних сущностях есть как дублирование данных, так и недостающая информация в дочерних корпоративных объектах (код страны).

Какие ограничения вы выберете, будет зависеть от вашего поставщика СУБД и от того, какой головной болью вы хотите управлять.

0 голосов
/ 19 июня 2009

Я согласен с остальными, что поле customerType должно быть достаточно, если разные типы клиентов похожи.

при этом, возможно, только корпоративные клиенты имеют общую таблицу, но государственные клиенты настолько различны, что их необходимо определить в своей собственной таблице. в случае, если это оправдано, одна из схем, которая поможет вам реализовать ограничение PK, будет иметь таблицу MasterAccount, которая будет ссылаться на всех клиентов по идентификатору (ограничение PK), и иметь ссылку на их тип на следующем уровне иерархия (корпоративная или государственная).

вам все еще нужно отобразить отношения 1- *, что вы можете сделать с помощью еще двух таблиц - таблицы взаимосвязей и таблицы сопоставления учетных записей.

0 голосов
/ 19 июня 2009

Я думаю, у вас должны быть только учетная запись и таблица клиентов, а также таблица CustomerRelationship. Различные типы клиентов могут различаться с помощью некоторого кода типа, а отношения могут поддерживаться с помощью таблицы CustomerRelationship.

0 голосов
/ 19 июня 2009

Если нет существенной разницы в атрибутах, которые отслеживаются среди разных типов клиентов, я бы просто имел одну таблицу с именем Account с некоторым полем CustomerType. Вы можете выразить отношение 1: m в таблицах сведений, имеющих FK и AccountID.

Редактировать: Современные базы данных могут добавлять правила целостности данных помимо ссылочной целостности FK. Например, в SQL Server вы можете добавить CHECK Constraints , чтобы AccountType стал GovernmentCustomer для главной таблицы подробных данных. Это может выглядеть примерно так:

CREATE FUNCTION EnforceGovernmentCustomer(@AccountID int)
RETURNS bit
AS 
BEGIN
   DECLARE @retval bit
   SELECT @retval = 0
   SELECT @retval = 1
   FROM Account
   WHERE AccountID = @AccountID AND AccountType = 3

   RETURN @retval
END;
GO
ALTER TABLE GovernmentCustomerDetail
ADD CONSTRAINT chkGovernmentCustomer CHECK (dbo.EnforceGovernmentCustomer(AccountID) = 1);
GO
...