Я знаю, что этот вопрос очень старый, но, поскольку на него еще нет принятого ответа, у меня есть пара идей.
Одна из возможностей — использовать возможности 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
также могут снизить производительность, и вы заметите как дублирование данных в дочерних объектах, так и отсутствие информации в корпоративных дочерних объектах (country_code).
Какие ограничения вы выберете, будет зависеть от вашего поставщика СУБД и от того, с какой головной болью вы хотите справиться.
20.07.2014