Foreign key mit mehreren Spalten aus verschiedenen Tabellen
Nehmen wir ein blödes Beispiel : ich habe viele Tiere, ein jedes mit einem NAMEN wie eine id und einen Typ (als KATZE oder HUND), schreiben wir es auf diese Weise (pseudo-code) :
TABLE ANIMALS (
NAME char,
ANIMAL_TYPE char {'DOG', 'CAT'}
PRIMARY KEY(NAME)
)
(zum Beispiel, ich habe eine KATZE namens Felix und einen Hund namens Pluto)
In einer anderen Tabelle möchte ich store die bevorzugte Nahrung für alle meine Tiere :
TABLE PREFERED_FOOD (
ANIMAL_NAME char,
PREF_FOOD char
FOREIGN KEY (ANIMAL_NAME) REFERENCES ANIMALS(NAME)
)
(zum Beispiel Felix liebt Milch, und Pluto mag Knochen)
Als ich mag würde, um zu definieren, eine Reihe von möglichen bevorzugte Lebensmittel Lagere ich in einer Dritten Tabelle der Lebensmittel-Typen, die für jede Art von Tier :
TABLE FOOD (
ANIMAL_TYPE char {'DOG', 'CAT'},
FOOD_TYPE char
)
(zum Beispiel, Hunde fressen Knochen und Fleisch, Katzen Essen Fisch und Milch)
Hier kommt meine Frage : ich möchte noch hinzufügen, dass eine ausländische Einschränkung in PREFERED_FOOD, so wie die PREF_FOOD ist ein FOOD_TYPE von SPEISEN mit LEBENSMITTELN.ANIMAL_TYPE=TIERE.TYP. Wie kann ich definieren, diese Fremdschlüssel, ohne duplizieren der ANIMAL_TYPE auf PREFERED_FOOD ?
Ich bin kein Experte mit SQL, so können Sie rufen Sie mich dumm, wenn ist es wirklich einfach 😉
- Das erste, was ich tun würde, ist mit den numerischen Tasten statt char keys
- Ich bin damit einverstanden, numerische Tasten sind wirklich besser, diese Dinge zu vereinfachen, wenn viele Anfänger denken, Sie sind wirklich unnötig.
- Können Sie haben einen Hund namens Felix so gut wie eine Katze namens Felix? Können Sie eine Katze namens Pluto, sowie einen Hund namens Pluto? Dies treibt an ', Was ist der Primärschlüssel der Tiere, Tisch?' — es ist immer hilfreich, explizit genannt werden, weil (wie Sie sagen können, aus meine Frage), was Sie offensichtlich können nicht offensichtlich sein, zu anderen Menschen. Die FK in der Bevorzugten Lebensmittel-Tabelle legt nahe, dass Sie können nicht zwei verschiedene Tiere mit dem gleichen Namen zur gleichen Zeit, aber das ist eine indirekte, aber vermutlich zuverlässig — Inferenz.
- Sie können auch einen db trigger zum erzwingen der Datenintegrität constraints. Auch Graben die char foreign keys, nur einen tag erstellen Tabelle zum speichern der Beschreibungen und verwenden Sie ids, um Aussehen em up
- Yeap, sicher, die pet name als primary key ist nicht gut. Ich schrieb es auf diese Weise zu veranschaulichen, die Frage. Die Frage war nur auf den letzten Punkt, und diese Tabellen sind nur ein blödes Beispiel ;-).
- (und ich halte die trigger-Vorschlag im Hinterkopf, du hast Recht, ich wollte nur zu halten auf foreign keys, aber wenn ich nicht Triggern könnte fast den job machen)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kann man nicht in SQL. Ich denke, Sie könnte wenn SQL unterstützte Behauptungen. (Der SQL-92-standard definiert Behauptungen. Niemand unterstützt Sie noch, so weit ich weiß.)
Arbeiten, um das problem zu beheben, verwenden überlappende Einschränkungen.
animals_preferred_food
Tabelle kann komplett eliminiert werden, in diesem Fall. Die single Lieblingsessen pro Tier könnte dargestellt werden durch ein Feld in deranimals
Tabelle.animal_food_types
Tabelle ist, oder? Ich war reden die Beseitigunganimals_preferred_food
.in der PREFERRED_FOOD Tabelle, das wird stellen Sie sicher, dass jeder PREFFOOD in der PREFERRED_FOOD Tabelle ist bereits in der FOOD_TYPE der LEBENSMITTEL-Tabelle.
sowie in der LEBENSMITTEL-Tabelle verwenden, es ist ziemlich selbsterklärend jetzt.
Je nachdem, was DBMS du verwendest (bitte Editiere deine Frage, um diese aufzunehmen), würde Sie wahrscheinlich wollen, um eine unique-Einschränkung erstellen, die auf die
ANIMAL_TYPE
undPREFERED_FOOD
Spalten.Etwas wie dieses:
Ehrlich gesagt, hatte ich einige Schwierigkeiten, sich an Ihre Anforderungen, aber ein unkompliziertes Modell für die Darstellung von Tieren und Ihrer Nahrung würde wohl so Aussehen:
Den SPECIES_FOOD listet alle Lebensmittel eine bestimmte Art Essen kann, und die Person, dann nur die picks von Ihnen durch die PREFERRED_FOOD_NAME Feld.
Da der EINZELNE.SPECIES_NAME ist ein FK in Richtung beide ARTEN und SPECIES_FOOD, ein einzelner kann niemals bevorzugen eine Ernährung, die nicht essbar ist, indem Sie seine Arten.
Diese natürlich übernimmt ein einzelnes Tier nicht mehr als einen bevorzugten Speisen.1 Es wird auch davon ausgegangen, es können keine haben - wenn das nicht der Fall, stellen Sie einfach die EINZELNEN.PREFERRED_FOOD_NAME NICHT NULL.
Den INDIVIDUAL_NAME wurde absichtlich nicht machte einen Schlüssel, so dass Sie haben können, sagen wir, zwei Katzen mit den Namen "Felix". Wenn das nicht erwünscht ist, werden Sie einfach fügen Sie die entsprechende Taste.
Wenn alles, was Sie wissen müssen über die Nahrung ist, seinen Namen, und Sie brauchen nicht zu vertreten, einem Lebensmittel unabhängig von jeder Spezies, die LEBENSMITTEL-Tabelle kann verzichtet werden, insgesamt.
1 In-Fall es kann mehrere bevorzugte Lebensmittel pro Person, Tier, brauchen Sie eine weitere Tabelle "zwischen" INDIVIDUUM und SPECIES_FOOD, und vorsichtig sein, um mit der Ermittlung der Beziehungen, so SPECIES_NAME migriert alle der Weg nach unten (um zu verhindern, dass die lieber ein Essen nicht genießbar, die von der Art).
Wenn man die (Natürliche) JOIN von TIEREN und PREFERRED_FOOD, dann bekommst du eine Tabelle, in der für jedes Tier, seine Art und seine bevorzugte Nahrung sind aufgeführt.
Du willst, dass die Kombination "gültig" für jedes einzelne Tier, wo "gültig" bedeutet "erscheinen in der Aufzählung der gültigen Tierart/Lebensmittel-Typ-Kombinationen, die aufgeführt sind in der NAHRUNG.
So eine Einschränkung, das ist etwas ähnliches wie ein FK, aber dieses mal sind die "foreign key" erscheint nicht in einem base-Tabelle, sondern in einer Verknüpfung von zwei Tabellen. Für diese Art der Einschränkung, die SQL-Sprache hat sich CHECK-Einschränkungen und ASSERTIONEN.
Die GELTENDMACHUNG version ist die einfachste. Es ist eine Einschränkung wie (ich habe etwas liberal mit den Attribut-Namen, um zu vermeiden, bloße Attribut benennt das verschleiern der Punkt)
Aber Ihre Durchschnittliche SQL-engine wird nicht unterstützt Behauptungen. So Sie haben zu Verwendung von CHECK-Einschränkungen. Für die PREF_FOOD Tabelle, zum Beispiel die CHECK-Einschränkung müssen Sie Aussehen könnte so etwas wie
In der Theorie sollte diese genügen, um zu erzwingen, Ihre Einschränkung, aber dann wieder Ihre Durchschnittliche SQL-engine wird wieder einmal keine Unterstützung für diese Art von CHECK-Einschränkung, da die Verweise auf die Tabellen andere als die, die die Einschränkung definiert ist.
So die Optionen, die Sie haben, ist der resort eher Komplex (*) setups wie Pfeifen, oder der Durchsetzung der Einschränkung der Verwendung von Triggern (und Sie haben zu schreiben, eine ganze Menge von Ihnen (drei oder sechs zumindest noch nicht durchdacht im detail), und Ihre nächste beste option ist, um dies durchzusetzen, im code der Anwendung, und noch einmal gibt es drei oder sechs (mehr oder weniger) unterschiedliche Orte, an denen die gleiche Anzahl von unterschiedlichen Prüfungen umgesetzt werden müssen.
In all diesen drei Szenarien, werden Sie vorzugsweise dokumentieren wollen, die Existenz der Einschränkung, und was genau es ist, an einem anderen Ort. Keiner der drei wird es sehr offensichtlich, zu einer Dritten Lesung dieses design, was zum Teufel das alles soll.
(*) "Komplex" ist vielleicht nicht genau das richtige Wort, aber beachten Sie, dass diese Lösungen stützen sich auf bewusste Redundanz, so bewusst unter 3NF mit dem design. Und das bedeutet, dass Ihr design ist ausgesetzt-update-Anomalien, was bedeutet, dass es dann schwieriger wird für den Benutzer, die Datenbank zu aktualisieren UND konsistent halten (gerade wegen der bewusste Redundanzen).