2

我正在查看我提出的这个数据模型并且感觉不舒服。我已经更改了实体名称,所以它(希望)更有意义。无论如何,您将如何建模以下内容?

我有 3 个实体。政府客户、私人客户、公共客户。私人客户和公共客户都是公司客户。企业和政府客户是账户。所有帐户共享相同的密钥空间(因此,如果 PrivateCustomer 的 PK 为 1,那么 Public 或 GovernmentCustomer 的 PK 不应该为 1)。CorporateCustomer 有一些GovernmentCustomer 没有的1:M 关系。PublicCustomers 有一些 PrivateCustomers 没有的 1:M 关系。

传承:

Account
  CorporateCustomer
    PrivateCustomer
    PublicCustomer
  GovernmentCustomer

现在我的模型有 5 张桌子。“Account”表是这个层次结构的根,每个子表的 PK 是其父 PK 的 FK。所以所有的表都有相同的PK。

所以,是的,你将如何建模?我希望这里没有出现严重错误:)。

编辑:

另外: - 我希望数据库负责参考完整性而不是应用程序。- 如果没有私人或公共客户,CorporateCustomer 就不可能存在。它的抽象。

4

6 回答 6

1

一种方式可能是:

ACCOUNTS -> ACCOUNT_CUSTOMERS <- CUSTOMERS

使 CUSTOMERS 具有类型为 Corporate(C)、Private(P)、Public(Z)、Government(G) 的 CUSTOMER_TYPE 列。由于所有公共和私人客户也是企业,如果您需要获得所有企业客户,您可以执行以下操作:

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'
于 2009-06-19T04:29:14.660 回答
1

在您承诺将每个类放在同一个表中之前,我会查看它们所涉及的关系- 而不是属性。如果记录类型为“X”,则将某些字段保留为空是微不足道的,但尝试建立仅适用于表中某些记录的关系是非常笨拙的。

如果类与其他实体的关系完全相同,那么您可以将它们全部填充到一个表中,而没有真正的缺点。

于 2011-04-28T22:46:24.920 回答
0

我知道这个问题已经很老了,但是由于它还没有一个公认的答案,所以我有几个想法。

一种可能性是使用 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);

不同的 DBMS 供应商将以不同的方式实现这一点。在 PostgresSQL 中,这里描述了一些重要的警告:

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

特别要注意关于主键和外键不被继承的部分。

如果您不喜欢 DBMS 的限制或正在使用不具有对象关系功能的 DBMS,那么另一种选择是使用上面文章中建议的替代方法并使用辅助键。那将是这样建模的:

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) 中缺少信息。

您选择哪些限制将取决于您的 DBMS 供应商以及您想要管理的头痛程度。

于 2014-07-20T06:03:45.833 回答
0

我同意其他人的观点,即如果不同类型的客户相似,customerType 字段就足够了。

也就是说,也许只有企业客户共享一个表,但政府客户的差异很大,需要在自己的表中定义。如果这是有保证的,帮助您实施 PK 约束的一种设计是拥有一个 MasterAccount 表,该表将通过 id 引用所有客户(PK 约束),并在下一级引用他们的类型层次结构(公司或政府)。

您仍然需要映射 1-* 关系,您可以使用另外两个表来执行此操作 - 关系表和帐户关系映射表。

于 2009-06-19T04:58:49.503 回答
0

除非在不同类型的客户之间跟踪的属性存在显着差异,否则我只会有一个名为 Account 的表,其中包含一些 CustomerType 字段。您可以通过具有 FK 到 AccountID 的明细表来表达 1:m 关系。

编辑:现代数据库可以在 FK 参照完整性之外添加数据完整性规则。例如,对于 SQL Server,您可以添加CHECK 约束以强制 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
于 2009-06-19T04:21:34.860 回答
0

我认为您应该只有一个 Account 和一个 Customer 表,以及一个 CustomerRelationship 表。不同类型的客户可以使用某种类型代码来区分,并且可以使用 CustomerRelationship 表来维护关系。

于 2009-06-19T04:22:35.017 回答