7
votes

Touche étrangère avec plusieurs colonnes de différentes tables

Prenons un exemple stupide: j'ai de nombreux animaux domestiques, chacun avec un nom comme une pièce d'identité et un type (chat ou chien), écrivons-le de cette façon ( pseudo code ): xxx

(par exemple, j'ai un chat nommé Felix, et un chien appelé Pluto)

dans une autre table, je voudrais stocker les aliments préférés pour chaque un de mes animaux: xxx

(par exemple, Felix aime le lait, et Pluto aime les os)

Comme je voudrais définir un ensemble de possibilités possibles Les aliments préférés, je stocke dans une troisième table les types de nourriture, pour chaque type d'animal: xxx

(par exemple, les chiens mangent des os et de la viande, des chats mangent du poisson et du lait)

Voici ma question: J'aimerais ajouter une contrainte étrangère dans la préfecture_food, de sorte que la préf_food est un aliment_type de nourriture avec de la nourriture.Animal_type = animaux.Type. Comment puis-je définir cette clé étrangère sans dupliquer l'animal_type sur préféré_food?

Je ne suis pas un expert avec SQL, vous pouvez donc m'appeler stupide s'il est vraiment facile; -)


6 commentaires

La première chose que je ferais est d'utiliser des touches numériques au lieu de clés de caractère


Je suis d'accord, les clés numériques sont vraiment meilleures, elles simplifient les choses, bien que de nombreux débutants pensent qu'ils sont vraiment inutiles.


Pouvez-vous avoir un chien nommé Felix ainsi qu'un chat nommé Felix? Pouvez-vous avoir un chat nommé Pluto ainsi qu'un chien nommé Pluton? Cela conduit à 'Quelle est la clé principale de la table des animaux? " - Il est toujours utile d'être explicite car (comme vous pouvez le dire à ma question), ce qui est évident pour vous ne pouvez pas être évident pour les autres personnes. Le FK dans la table alimentaire préférée suggère que vous ne pouvez pas avoir deux animaux de compagnie différents avec le même nom en même temps, mais c'est une inférence indirecte - mais probablement fiable.


Vous pouvez également utiliser un db déclencheur à appliquer les contraintes d'intégrité des données. Également fossé les clés étrangères Char, créez simplement une table d'étiquette pour stocker les descriptions et utiliser des identifiants pour les regarder


Yeap, sûr, le nom de l'animal comme clé primaire n'est pas agréable du tout. Je viens de l'écrire de cette façon d'illustrer la question. La question n'était que sur le dernier point et ces tables sont juste un exemple stupide ;-).


(Et je garde la suggestion de déclenchement à l'esprit, vous avez raison, je voulais juste rester sur des clés étrangères, mais si je ne peux pas que les déclencheurs puissent presque faire le travail)


5 Réponses :


0
votes
FOREIGN KEY (ANIMAL_TYPE) REFERENCES ANIMALS (ANIMAL_TYPE)

2 commentaires

animaux.Animal_type n'est pas unique. Si ce n'est pas unique, vous ne pouvez pas l'utiliser comme cible pour une contrainte de clé étrangère. (Sauf dans MySQL, où ils avertissent vous ne devez pas le faire dans la documentation, mais ne stop vous faites comme tout le SAND DBMS.)


Qu'est-ce que "Sane" à propos de cette restriction? Les cours ne peuvent être organisés que dans des villes où nous avons un département. La ville n'est pas une clé pour le département. Pourtant, la règle en soi n'est toujours rien de plus que des références de CRS (ville) '...



0
votes

Selon ce que vous utilisez SGMS (veuillez éditer votre question pour inclure ceci), vous voudrez probablement créer une contrainte unique sur le animal_type et préféré_food Colonnes.

quelque chose comme ceci: xxx


1 commentaires

Yeap, bien sûr aussi ;-). Mais la question que j'avais était seulement sur l'ajout d'une clé étrangère avec de multiples colonnes et des contraintes provenant de différentes tables ;-) (et ce n'était qu'une question générale de SQL, je n'ai aucun SGBD en tête)



3
votes

Vous ne pouvez pas en SQL. Je pense que vous pourrait em> si SQL a appuyé les assertions. (Les affirmations définies standard SQL-92. Personne ne les soutient encore, autant que je sache.)

Travailler autour de ce problème, utilisez des contraintes de chevauchement. P>

-- Nothing special here.
create table animal_types (
  animal_type varchar(15) primary key
);

create table animals (
  name varchar(15) primary key,
  animal_type varchar(15) not null references animal_types (animal_type),
  -- This constraint lets us work around SQL's lack of assertions in this case.
  unique (name, animal_type)
);

-- Nothing special here.
create table animal_food_types (
  animal_type varchar(15) not null references animal_types (animal_type),
  food_type varchar(15) not null,
  primary key (animal_type, food_type)
);

-- Overlapping foreign key constraints.
create table animals_preferred_food (
  animal_name varchar(15) not null,
  -- This column is necessary to implement your requirement. 
  animal_type varchar(15) not null,
  pref_food varchar(10) not null,
  primary key (animal_name, pref_food),
  -- This foreign key constraint requires a unique constraint on these
  -- two columns in "animals".
  foreign key (animal_name, animal_type) 
    references animals (animal_name, animal_type),
  -- Since the animal_type column is now in this table, this constraint
  -- is simple.
  foreign key (animal_type, pref_food) 
    references animal_food_types (animal_type, food_type)
);


6 commentaires

ok, alors je dois ajouter l'animal_type dans la deuxième table :-( (Eh bien, vous mettez ici comme faisant partie de la clé, il semble donc logique, mais si vous imaginez que la seule clé est le nom de l'animal, c'est une duplication. :-() Merci pour la réponse, je vais chercher à affirmer, je ne sais pas à ce sujet!


@ user1695584 Avez-vous vraiment besoin de plusieurs aliments préférés par animal?


@Brankodimitrijevic: J'ai complètement négligé ce point. Je vais blâmer mon chien pour ça. La clé primaire de cette table devrait probablement être «Nom de l'animal». Je vais attendre que le point op de vérifier.


@CatCall En outre, animaux_preferred_food La table peut être complètement éliminé dans ce cas. Le seul aliment préféré par animal pourrait être représenté par un champ dans la table .


@Brankodimitrijevic: Une partie du point de la question stockait une préférence appropriée pour chaque type d'animal. Pour ce faire, vous devez stocker "la nourriture [nourriture_type] est un aliment approprié pour les animaux de [animal_type]."


@CatCall et c'est ce que animal_food_types est pour, non? Je parlais d'éliminer animaux_preferred_food .



0
votes

Franchement, j'ai eu des difficultés à suivre vos besoins, mais un modèle simple pour représenter les animaux et leur nourriture ressemblerait probablement à ceci:

Entrez la description de l'image ici

L'espèce_food répertorie tous les aliments qu'une espèce donnée peut manger et que l'individu choisit alors l'un d'entre eux via le champ préféré_food_name.

Depuis individu.Species_Name est un FK vers Espèces Specess_Food, une personne ne peut jamais préférer un aliment non comestible par son espèce.

Ceci assume bien sûr qu'un animal individuel ne peut pas avoir plus d'un aliment préféré. 1 Il suppose également qu'il ne peut en avoir pas - si ce n'est pas le cas, faites simplement l'individu.preferred_food_name pas null. < / p>

Le nom individuel était intentionnellement pas fait une clé, vous pouvez donc avoir, disons, deux chats avec le nom "Felix". Si ce n'est pas souhaitable, vous ajouterez facilement la clé appropriée.

Si tout ce que vous avez besoin de savoir sur la nourriture est son nom et que vous n'avez pas besoin de représenter un aliment de manière indépendante de toutes les espèces, la table alimentaire peut être complètement omise.


1 au cas où il peut y avoir plusieurs aliments préférés par animal individuel, vous auriez besoin d'une autre table "entre" individuel et espèce_food, et veillez à continuer à utiliser des relations d'identification. Noms espèces est donc migré. jusqu'au bout (pour éviter de préférer un aliment non comestible par l'espèce).


0 commentaires

0
votes

Si vous prenez la jointure (naturelle) d'animaux et de préféré_food, vous obtenez une table dans laquelle pour chaque animal, son type et ses aliments préférés sont répertoriés.

Vous voulez que cette combinaison soit "valide" pour chaque animal individuel où "valide" signifie "apparaître dans l'énumération des combinaisons de type animal / type d'alimentation valides répertoriées dans la nourriture.

Vous avez donc une contrainte quelque peu similaire à un FK, mais cette fois-ci la "clé étrangère" n'apparaît pas dans une table de base, mais dans une jointure de deux tables. Pour ce type de contrainte, la langue SQL a vérifié les contraintes et les affirmations.

La version d'affirmation est la plus simple. Il est une contrainte comme (j'ai été un peu libérale avec les noms d'attributs afin d'éviter un simple attribut renommé qui obfusez le point) xxx

mais votre moteur SQL moyen ne sera pas Soutenir les assertions. Vous devez donc utiliser des contraintes de contrôle. Pour la table Pref_Pood, par exemple, la contrainte de contrôle dont vous avez besoin pourrait ressembler à quelque chose comme xxx

En théorie, cela devrait suffire à appliquer votre contrainte, mais encore une fois, votre moteur SQL moyen ne prend une fois à nouveau pas en charge ce type de contrainte de contrôle, en raison des références à des tables autres que celui de la contrainte définie.

Les options que vous avez sont nécessaires pour recourir à des configurations assez complexes (*) telles que Catcall, ou en appliquant la contrainte en utilisant des déclencheurs (et vous devrez écrire beaucoup d'entre eux (trois ou six au moins, Haven 'T Pensez-y en détail) et votre prochaine meilleure option consiste à appliquer ceci dans le code de la demande, et encore une fois, il y aura trois ou six lieux distincts dans lesquels le même nombre de contrôles distincts doit être mis en œuvre.

Dans tous ces trois scénarios, vous voudrez de préférence documenter l'existence de la contrainte et quoi exactement il s'agit, dans un autre lieu. Aucun des trois ne le rendra très évident pour une tierce partie à lire cette conception ce que le diable est tout à propos.

(*) "complexe" pourrait ne pas être le mot juste, mais notez que de telles solutions compter sur redondance délibérée , donc passant délibérément en dessous de 3nf avec la conception . Et cela signifie que votre conception est exposée à la mise à jour des anomalies, ce qui signifie qu'il sera plus difficile pour l'utilisateur de mettre à jour la base de données et de le garder cohérent (précisément en raison des licenciements délibérés).


0 commentaires