6
votes

Puis-je créer un champ d'identité sur plusieurs tables dans SQL Server?

Puis-je avoir une colonne "identité" (unique, non répétée) de plusieurs tables? Par exemple, disons que j'ai deux tables: livres et auteurs.

Authors
  AuthorID
  AuthorName
Books
  BookID
  BookTitle


0 commentaires

5 Réponses :


0
votes

comme une suggestion - essayez d'utiliser une table comme le comentid, l'entitéIdid, l'isbook, commentaire pour commentaires. isbook est un type booléen et pas beaucoup de place à obtenir. Votre concept n'est pas bon du point de vue relationnel.


0 commentaires

5
votes

Même si vous pouviez mettre la séquence d'identité sur plusieurs tables, votre table de commentaire ne sera pas en mesure de référencer les deux colonnes dans une seule clé étrangère.

Le meilleur moyen de le faire, en termes de conception de la base de données relationnelle La théorie serait de créer deux tables de commentaire. Mais évidemment, vous voulez éviter cela, probablement pour des raisons de réutilisation de code. P>

L'approche pragmatique la plus simple serait de mettre deux colonnes de clé étrangère sur la table de commentaire et de faire une null et l'autre non null pour chaque commentaire. P>

Une autre approche, qui pourrait être le meilleur compromis, est-ce. Vous vous référez dans votre question à une "ID d'entité". Alors faites une table d'entité! Ensuite, les auteurs et les livres et les commentaires peuvent tous se référer à que em> table. P>

édité pour ajouter: strong> p>

Philip Kelley, Ray et (je pense) artic ont tous suggéré de modifier la table de commentaire en ajoutant un entity_id code>, qui peut se référer à la book_id code> ou au auteure_id code> et un drapeau de quelque sorte ( char (1) code>, tinyint code> et booléen code> respectivement) qui indique laquelle d'entre eux est en train d'être référé à celle-ci. . P>

Ce n'est pas une bonne solution pour de nombreuses raisons, à la fois pragmatique (y compris l'intégrité des données, la déclaration, l'efficacité) et théorique. P>

Le problème de l'intégrité des données est le problème de l'intégrité des données. . Un système de base de données relationnelle doit toujours être responsable du maintien de l'intégrité de ses propres données, et des moyens naturels et préférés que la DB est conçue pour le faire. L'un des plus importants de ces mécanismes est le système de clés étrangers. Si la colonne COMMENTAY_ID CODE> est de référencer les deux book.book_id_id code> et auteure.author_id code>, une clé étrangère ne peut pas être créée pour cette colonne. p>

Assurez-vous, vous pouvez enregistrer vos procédures stockées DML (Insérer, mettre à jour, supprimer) pour vérifier les références, mais cela se transformerait rapidement en un grand désordre, car toutes les opérations DML sur les trois tableaux seraient être impliqué. p>

et cela nous conduit au problème d'efficacité. Chaque fois qu'une requête est exécutée contre le tableau code> code>, il nécessitera des jointures à l'auteur code> ou book code> table ou les deux. Le système de génération de plan de requête ne disposera pas de clés étrangères disponibles pour optimiser avec, de sorte que sa performance pourrait très bien être dégradée. P>

Il y a des problèmes de ce schéma dans la déclaration. Tout système générateur de rapport va avoir des problèmes avec ce type de système. Bien sûr, cela ne posera pas de problème pour les programmeurs d'experts, mais tout utilisateur ad hoc devra se moquer de la logique de la logique lorsque le event_id code> signifie ceci ou cela, et cela pourrait être une jolie mauvaise affaire. Peut-être que vous n'utiliserez jamais des outils générant des rapports sur cette base de données. Mais là encore, personne ne sait où une base de données sera finalement utilisée. Pourquoi ne pas travailler avec le système pour laisser quoi que ce soit? P>

et cela nous conduit aux problèmes théoriques. P>

Dans la théorie de la base de données relationnelle, chaque ligne (alias "tuple") dans chaque table («Variable de relation») représente une proposition sur le monde réel. La conception d'une table est de décider de la forme de cette proposition. Regardons quelques exemples de la façon dont cela pourrait fonctionner. P> xxx pré>

ici Il est clair que la colonne (ou "attribut") appelée entity_id code> est faire double service. Cela ne représente rien vraiment, sauf en référence à une autre colonne. Ceci est fonctionnel, mais insatisfaisant. P> xxx pré>

Cela nous achète les clés étrangères qui sont la plus grande omission de la première version. Mais cela n'est toujours pas terriblement satisfaisant, à moins qu'un seul commentaire puisse faire référence à la fois à un livre et à un auteur (ce qui pourrait être raisonnable). Les colonnes nullables sont un signe d'avertissement que quelque chose ne va pas avec la conception, ce qui peut être le cas ici aussi. Une contrainte de contrôle peut être nécessaire pour éviter un commentaire qui ne fait référence à rien, à la fois un livre et un auteur si cela ne doit pas être autorisé. P>

d'une perspective théorique (et donc, mon point de vue :)) Il y a une option optimale: p> xxx pré>

Cette dernière option fournirait la meilleure efficacité, l'intégrité des données et la facilité de reporting. Et la seule dépense serait que les procédures stockées DML auraient besoin de mettre les commentaires dans les bonnes tables, ce qui n'est pas une grosse affaire, car ils devaient savoir ce que les commentaires faisaient référence à de toute façon. P>

si Votre plan était de revenir tous les commentaires d'un livre ou d'un auteur à la fois, vous pouvez facilement créer une vue sur ces tables qui reproduit les autres conceptions, si c'est ce que vous voulez faire. P>

create view comments as 
select 
    book_comment_id as comment_id, 
    book_id as entity_id, 
    comment_text,
    'B' as comment_type
from book_comment
union
select 
    author_comment_id as comment_id, 
    author_id as entity_id, 
    comment_text,
     'A' as comment_type 
from author_comment


7 commentaires

Bonjour Jeffrey, pourquoi pensez-vous que c'est une mauvaise idée d'utiliser un "ID de type commentateur" avec l'ID d'entité "? Pourquoi vos deux dernières suggestions sont-elles mieux? Je continue d'apprendre! Merci.


Ceci, imo, est la bonne réponse. L'utilisation d'une structure EAV pour ce type de solution est la mauvaise réponse et deviendra laide dans les rapports. L'ajout d'une autre table ne coûte vraiment pas beaucoup de choses mais fournit de nombreux avantages, notamment la capacité des commentaires de l'auteur à avoir des attributs que les commentaires du livre ne le font pas.


Une colonne de discriminator avec plusieurs références n'est pas EAV car @Thomas le suggère, cela ressemble plus à une héritage multiple (sauf qu'il n'est pas utilisé pour l'héritage dans cette question particulière, c'est donc ... bizarre). Néanmoins, je dirais que, compte tenu des spécifications de la question, c'est la meilleure réponse. Si la performance de l'application est un problème (c'est-à-dire que vous devez pouvoir traverser la relation à partir d'un à un book ou auteure sans vous joindre à tous Les tables de cartographie), cela pourrait toujours être dénormalisé avec une colonne discriminatrice dans la table sans sacrifier RI.


Merci pour l'explication. Qu'en est-il de la fin de votre message d'origine où vous suggérez "Vous vous référez dans votre question à une" pièce d'identité d'entité ". Donc, faites une table d'entité! Ensuite, les auteurs et les livres et les commentaires peuvent tous se référer à cette table." Voulez-vous dire avoir une table où la colonne «discriminateur» existerait. C'est-à-dire que vous auriez deux colonnes: entitéïde, entitéype. Ensuite, mon bookid (dans la table des livres) serait identique à mon entité et je peux simplement faire référence à l'entité dans ma table de commentaires. (suite ci-dessous)


Je comprends les avantages d'avoir différentes tables de commentaires pour différentes entités, mais j'essaie de rendre cette évolutive pour les nouvelles entités. Par exemple, plus tard, je souhaiterais peut-être ajouter des "magasins de livre" à mon schéma. J'aimerais pouvoir simplement «activer» les commentaires de la nouvelle "livret magasin" au lieu de créer une nouvelle table de commentaires. Et "commentaires" n'est qu'un exemple. Je pourrais faire la même chose pour les évaluations, les critiques, les tags, etc. Je suis assez nouveau dans ce type de programmation, alors je suis désolé si certaines de mes explications ne sont pas claires. J'apprécie vos efforts ici. Merci.


L'option Table de l'entité serait tout comme vous le décrivez, sauf que je ne voudrais pas nécessairement mettre la colonne de la contre-descinciatrice dans celle non plus, car elle serait redondante avec l'existence d'une rangée d'une autre table. Cela pourrait être une bonne idée dans ce cas, cependant, s'il y a beaucoup de types d'entités à rechercher. Si vous élargissez le système comme vous le dites avec plus de types d'entité et plus de choses référencées des entités, alors «une entité» devient plus significative qu'un concept, et une table pour tenir de telles choses en vaut la peine. On dirait que c'est la conception que vous devriez persuader.


Donc, fondamentalement, j'ai juste besoin d'une table avec une colonne (identité) qui génère la valeur d'identification que chaque entité utilisera? Semble avoir du sens pour moi; Je ne pense pas que j'ai jamais eu une table une colonne auparavant.



3
votes

La réponse courte est la suivante: Non, vous ne pouvez pas le faire (au moins dans MS SQL Server jusqu'en 2008).

Vous pouvez créer une nouvelle table, "CommanAturyENTity", branchez votre colonne d'identité, puis définissez des clés étrangères dans des auteurs et des livres pour y réfrir en tant que table parent, puis effectuez un certain nombre de tours pour vous assurer qu'un La valeur d'identification donnée n'est pas attribuée aux deux tables ... mais c'est une mauvaise idée, car le modèle de données que vous avez construit impliquerait que les auteurs et les livres sont des types de données connexes, et ils ne sont vraiment pas.

Vous pourriez avoir une table séparée, des commentaires, une colonne d'identité de là et garer une colonne commente dans les auteurs et les livres. Cependant, cela limiterait chaque livre et auteur à un seul commentaire.

Moi, j'ajouterais probablement une colonne comme "Commenterype" à la table des commentaires et un drapeau enfilé en indiquant la source de commentaire ("A" pour l'auteur, "B" pour le livre). Construisez une clé primaire sur "COMMENTORID + COMMENTORTYPETYPE", et il devrait fonctionner assez bien - et il serait trivial pour ajouter d'autres types de commentateurs à mesure que le système se développe.


3 commentaires

Vous ne pouvez pas avoir un seul point de clé étrangère à deux tables différentes, même avec un drapeau à portée de main.


Votre suggestion ("J'ajouterais probablement une colonne comme" commentatype "aux commentaires") est le chemin que je me suis dirigé avant de décider de poster et de veiller à ce qu'il n'y ait pas un moyen plus facile de le faire. Merci.


Mais l'ajout de type de commentateur aux commentaires n'est pas une bonne solution! Ne fais pas ça! Tu vas le regretter! Ok, je me sens mieux maintenant. Passer sur.



0
votes

SQL Server ne supporte pas cela. Vous pouvez rouler le vôtre avec une table d'identité, mais ce serait plus de travail que ce qu'il en vaut.

Je suggère que votre table de commentaire ressemble à ceci: p>

comment_id int identity
comment_type tinyint
entity_id int


0 commentaires

4
votes

En fait, Joe Celko suggère sur Ceci Blog pour utiliser une séquence personnalisée dans votre base de données, puis, pour une clé primaire de vos tables souhaitées, spécifiez leurs valeurs par défaut pour obtenir le numéro suivant à partir de votre séquence personnalisée.

Voici un échantillon de code de son Blog: P>

CREATE SEQUENCE Service_Ticket_Seq
 AS INTEGER
 START WITH 1
 INCREMENT BY 1
 MINVALUE 1
 MAXVALUE 100
 CYCLE;

CREATE TABLE Meats
(ticket_seq INTEGER DEFAULT NEXT VALUE FOR Service_Ticket_Seq
       PRIMARY KEY,
 meat_type VARCHAR(15) NOT NULL);

CREATE TABLE Fish
(ticket_seq INTEGER DEFAULT NEXT VALUE FOR Service_Ticket_Seq
       PRIMARY KEY,
 fish_type VARCHAR(15) NOT NULL);

INSERT INTO Meats (meat_type) VALUES ('pig');
INSERT INTO Fish (fish_type) VALUES ('squid');

select * from Meats

select * from Fish


1 commentaires

Je pense que c'est la bonne approche, a fonctionné excellent!