2010-10-08 10 views
8

Je travaille sur un programme dans lequel vous pouvez enregistrer des plaintes. Il existe trois types de plaintes: internal (erreurs des employés), external (erreurs d'une autre société) et supplier (erreurs commises par un fournisseur). Ils contiennent des données différentes qui ne peuvent pas être partagées. J'ai actuellement 4 tables (plainte, employé, compagnie et fournisseur). Voici une visualisation des tables:Comment appliquer des sous-types dans une base de données SQL Server?

J'ai une compréhension de base des sous-types, mais je ne peux pas les traduire à partir d'une ERD dans une base de données SQL Server réelle, ou du moins dans ce scénario. Ceci est à peu près comment les 4 tables regardent (attributs non pertinents omis):

plainte
ComplaintId PK

employé
EmployeeId PK
EmployeeName

Société
COMPANYID PK
CompanyName

Fournisseur
PK SupplierID
NomFournisseur

Lors de l'enregistrement d'une plainte, l'erreur est faite par l'une des 3 types et ils ont tous autre magasin d'informations. Quel est le meilleur moyen de stocker des informations dans ce cas? J'ai pensé à mettre 2 discriminateurs dans la table de plainte: ComplaintType et Id afin que je puisse pointer vers quelle table vérifier et quel ID j'ai besoin, mais ce n'est pas très propre et efficace.

Veuillez nous aider.

Répondre

4

Je vous recommande fortement de NE PAS utiliser la méthode "2 discriminateurs". Vous aurez effectivement une colonne de clé étrangère qui pointe vers l'une des trois tables, en fonction du champ ComplaintType. Si vous faites cela, vous contournerez les vérifications d'intégrité référentielle fournies par SQL Server et tous les avantages associés aux clés étrangères. Lors de mon précédent travail, il y avait une table appelée EntityTypeIndexLabel qui était une table de pont reliant IndexLabels (essentiellement des métadonnées) à diverses «entités», qui étaient de nombreuses tables potentielles différentes (Document, Binder, Workflow, etc ...). C'était tout simplement horrible. Le FK dans cette table pourrait pointer vers de nombreuses tables différentes. Les enregistrements orphelins peuvent apparaître partout. Une logique supplémentaire a dû être implémentée pour déterminer à quelle table se connecter. Les jointures étaient une douleur à écrire en général. C'était toutes sortes de maux de tête.

Je pense que vos deux options sont:

-3 colonnes dans la plainte: EmployeeComplaintID, CompanyComplaintID, SupplierComplaintID. ComplaintIDs doit être unique dans toutes les tables (pensez aux GUID ici au lieu des colonnes IDENTITY). Chaque rangée dans Complaint aura un seul de ces IDs rempli, les deux autres seront NULL. Ensuite, vous pouvez simplement quitter LEFT OUTER JOIN sur ces tables dans chaque requête pour obtenir les données dont vous avez besoin.

-Un tableau géant avec tous les champs possibles dont vous avez besoin pour chaque type de réclamation, définissant les champs non utilisés des autres types de réclamations sur NULL.

+0

Nous vous remercions de votre suggestion. Je vais certainement rester loin de la méthode des 2 discriminateurs. J'ai aussi essayé la méthode des 3 colonnes mais pas encore avec une sorte de contrainte. Est-il possible de forcer au moins un des champs à ne pas être nul? Si oui, comment feriez-vous cela? – Fusyion

+0

J'ai choisi d'accepter votre réponse comme «la réponse» car elle est informative et j'ai également choisi votre première option pour faire fonctionner les choses. – Fusyion

+0

@Mario Je ne vois pas comment une colonne ComplaintType et trois tables séparées seraient un problème. Chaque table enfant contient une clé étrangère à la table Parent. Voir ce violon: http://sqlfiddle.com/#!3/6118b6/2 Le seul problème est que l'on pourrait référencer mauvais parent, le parent de type incorect. Mais ceci peut être résolu avec l'introduction d'une contrainte supplémentaire et l'extension des clés étrangères.Voir ce violon: http://sqlfiddle.com/#!3/58cd0/1 Mais, comme SQL Server gaspille de l'espace en stockant des colonnes nulles j'irais avec une grande table ine pour tous les types et stocker des valeurs nulles dans des colonnes où cela ne s'applique pas. – Anderson

1

Est-ce que le principal problème est que vous avez besoin d'une sorte de "numéro de série" pour identifier de manière unique une plainte quel que soit le type? Fondamentalement, alors, vous avez besoin d'un tableau pour chaque type de plainte (comme vous l'aurez, je pense), plus le tableau principal "Plainte" avec le ComplaintId. Chacune des tables spécifiques au type aura une clé étrangère à Complaint.ComplaintId. Vous pouvez trouver utile d'avoir un champ "type" dans Plainte, mais ce n'est pas vraiment nécessaire pour le modèle.

+0

J'ai considéré avoir des tables distinctes pour chaque type de plainte, mais il y a simplement trop d'attributs dans chaque table qui sont redondants. – Fusyion

+0

Ensuite, mettez ces attributs dans le tableau principal "Plainte", en ne mettant que les éléments uniques dans chacune des tables plus spécifiques. – Andrew

1

Vous pouvez avoir un type de dépôt de plainte avec une relation FK avec le PK des trois tables de vos sous-types - employé, entreprise et fournisseur.

+0

J'ai essayé ceci, mais l'identifiant que vous entrez dans la table de plainte ne doit-il pas correspondre à celui des ** trois ** tables? – Fusyion

+0

non, l'un des trois. l'hypothèse est que les clés sont mutuellement exclusives. – Beth

+0

Je dois faire quelque chose de mal alors. J'ai créé un 'SubTypeId' dans ma table de plainte et j'ai créé une relation avec les clés primaires des trois tables. Je ne pouvais pas entrer d'identifiant sauf celui qui est le même sur les trois tables. – Fusyion

13

Voir quelques vraiment bonnes ressources sur le sujet:

Il y a essentiellement trois approches bien connues:

  • table par classe
  • Tableau par hiérarchie
  • Tableau par type béton

Chacun a des avantages et des inconvénients, resplendit dans une situation et succions dans d'autres - étudier les ressources et voir lequel des trois adapté à vos besoins le meilleur.

0

En réponse à toi sont commentaires sur la réponse acceptée:

Voici une façon d'avoir un chèque de contrôle pour assurer que l'une des trois touches comporte des données:

alter table complaint_master 
    add constraint loc_attribute_has_one_value 
    check ( 
     (case when complaint_employee is null then 0 else 1 end) + 
     (case when complaint_supplier is null then 0 else 1 end) + 
     (case when complaint_external is null then 0 else 1 end) = 1 
    );