2

Je regarde ce modèle de données que j'ai trouvé et ne me sens pas à l'aise. J'ai changé les noms des entités de sorte qu'il (on l'espère) a plus de sens. Quoi qu'il en soit, comment modéliseriez-vous ce qui suit?Comment modéliser cette relation d'héritage multiple avec un SGBDR?

J'ai 3 entités. GovernmentCustomer, PrivateCustomer, PublicCustomer. Les clients privés et publics sont tous les deux CorporateCustomers. Les clients Corporate et Government sont des comptes. Tous les comptes partagent le même espace clé (donc si PrivateCustomer a un PK de 1, il ne devrait pas être possible pour Public ou GovernmentCustomer d'avoir un PK de 1). CorporateCustomers a des relations 1: M que GovernmentCustomer n'a pas. PublicCustomers a des relations 1: M que PrivateCustomers n'ont pas.

L'héritage:

Account 
    CorporateCustomer 
    PrivateCustomer 
    PublicCustomer 
    GovernmentCustomer 

En ce moment, mon modèle dispose de 5 tables. La table "Compte" étant la racine de cette hiérarchie, le PK de chaque table enfant étant un FK du PK de son parent. Donc toutes les tables ont le même PK.

Alors ouais, comment modéliserais-tu cela? J'espère que quelque chose ne va pas vraiment mal ici :).

EDIT:

aussi: - Je voudrais que le DB à prendre en charge l'intégrité ref pas l'application. - Il n'est pas possible pour un CorporateCustomer d'exister sans être un client privé ou public. Son résumé.

Répondre

0

À moins qu'il y ait une différence significative dans les attributs qui sont suivis parmi les différents types de cusomter, je n'aurais qu'une seule table appelée Account avec un champ CustomerType. vous pouvez exprimer la relation 1: m par des tables de détail ayant FK à AccountID. Editer: Les bases de données modernes peuvent ajouter des règles d'intégrité des données au-delà de l'intégrité référentielle FK. Par exemple, avec SQL Server, vous pouvez ajouter CHECK Constraints pour appliquer AccountType à GovernmentCustomer pour le maître de la table de détails. Cela pourrait ressembler à ceci:

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 
+0

Si je comprends bien cette approche, mon application devrait gérer un peu l'intégrité des données.Par exemple, il serait possible pour un compte avec type GovernmentCustomer d'avoir plusieurs états financiers. Seules les entreprises clientes devraient avoir cette relation. Ai-je raison? J'ai mis à jour la question pour rendre l'intégrité de l'interface un peu plus claire. –

+0

@TheDeeno, j'ai mis à jour la réponse pour refléter votre entrée. –

+0

@ eed3si9n Merci! Je vais devoir voir si je peux modéliser cela en prenant en compte une contrainte de vérification personnalisée. Donc vous êtes généralement opposé à la table 5 partageant une idée PK? –

0

Je pense que vous devriez juste avoir une table Compte et Client, avec une table CustomerRelationship. Les différents types de clients peuvent être différenciés avec un code de type quelconque, et les relations peuvent être confirmées à l'aide d'une table CustomerRelationship.

1

One Way pourrait être:

ACCOUNTS -> ACCOUNT_CUSTOMERS <- CUSTOMERS 

Faire les clients ont une colonne de CUSTOMER_TYPE qui est de type d'entreprise (C), privé (P), Public (Z), Gouvernement (G). Étant donné que tous les clients publics et Pivate sont également entreprise si vous avez besoin pour obtenir tous les clients d'entreprise que vous pourriez faire quelque chose comme:

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') 

je syntaxe ORACLE, mais je pense que vous avez l'idée.

In response to your edit: 

Il semble que vous n'ayez que deux types de CLIENTS. Corporatif et gouvernement. C'est encore plus facile alors. J'utiliserais un indicateur booléen sur les CLIENTS appelé PUBLIC_IND que lorsque false est privé, ou un autre type comme ENTITY_TYPE qui pourrait être privé (P), public (Z), ou aucun (N).Ensuite, si vous voulez récupérer tous les utilisateurs publics de clients d'entreprise:

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

Si je comprends bien cette approche, les clients d'entreprise sont traités comme des entités distinctes des clients publics et privés. J'ai mis à jour la question pour clarifier ceci. CorporateCustomers ne peut pas exister sans être un client privé ou public. Cette approche peut-elle fonctionner dans ce cas? Fondamentalement, je ne suis pas sûr quand j'ai jamais eu un enregistrement avec «Z» pour le type. –

0

Je suis d'accord avec les autres qu'un champ de CustomerType devrait suffire si les différents types de clients sont similaires. Cela dit, peut-être que les entreprises clientes partagent une table, mais les clients gouvernementaux sont suffisamment différents pour être définis dans leur propre tableau. dans le cas où cela est justifié, une conception pour vous aider à appliquer la contrainte PK serait d'avoir une table MasterAccount qui référencerait tous les clients par id (la contrainte PK), et aurait une référence à leur type au niveau suivant de la hiérarchie (entreprise ou gouvernement). Vous devez toujours mapper les relations 1- *, ce que vous pourriez faire avec encore deux autres tables - une table de relation et une table de mappage de relation de compte.

+0

Donc, j'aurais 3 tables. MasterAccount (ID, CustomerType), CorporateCustomer (Id - FK sur MA) et GovernmentCustomer (ID - FK sur MA)? –

+0

Je suppose que cela ne ferait pas la différence entre public et privé très facile lors de l'interrogation de la table CorporateCustomer. Il serait préférable d'avoir la table maître de distinguer entre corp et gov, et avoir la table corp distinguer entre pub et priv. Peu importe comment vous le découpez, si vous ne pouvez pas garder tous les comptes sur la même table, l'application d'identifiants uniques à travers les tables devient compliquée. – akf

0

Avant de vous engager à mettre chaque classe dans la même table, je voudrais regarder les relations ils sont impliqués dans - pas les attributs. Il est trivial de laisser certaines zones nulles si le type d'enregistrement est 'X', mais il est incroyablement compliqué d'essayer d'avoir des relations qui ne s'appliquent qu'à certains enregistrements d'une table.

Si les relations des classes avec d'autres entités sont exactement les mêmes, vous pouvez les placer toutes dans une table sans réel inconvénient.

0

Je sais que cette question est très ancienne, mais comme elle n'a pas encore de réponse acceptée, j'ai quelques idées.

Une possibilité consiste à utiliser les fonctionnalités ORDBMS - en d'autres termes, utiliser l'héritage de table. Dans PostgreSQL vous pouvez le modeler comme ceci:

(Voir la documentation sur l'héritage 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); 

Différents fournisseurs de SGBD mettront en œuvre ce de différentes manières. En PostgresSQL, il y a quelques mises en garde décrites ici:

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

En particulier, notez la partie sur les clés primaires et étrangères ne sont pas héritées. Si vous n'aimez pas les limitations de votre SGBD ou si vous utilisez un SGBD qui n'a pas de fonctions relationnelles, une autre option est d'utiliser une alternative suggérée dans l'article ci-dessus et d'utiliser des clés secondaires. Ce serait modelé comme ceci:

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) 
); 

La conception ci-dessus a des limites importantes aussi (qui sont également décrits dans l'article ci-dessus). D'une part, bien qu'il ne devrait pas être possible d'avoir un compte qui n'est pas un client privé, public ou gouvernemental, il est possible de le faire; on ne peut avoir que des comptes, des comptes d'entreprises qui ne sont ni publics ni privés ... cela devient un cauchemar à entretenir. Les contraintes CHECK peuvent également nuire aux performances, et vous remarquerez qu'il existe à la fois une duplication de données dans les entités enfants et des informations manquantes dans les entités enfants d'entreprise (code_pays).

Les limites que vous choisissez dépendront de votre fournisseur de SGBD et de la quantité de maux de tête que vous souhaitez gérer.

Questions connexes