Ihr aktuelles Design heißt exklusive Bögen wo der sets
table hat zwei Fremdschlüssel und benötigt genau einen davon, um nicht null zu sein. Dies ist eine Möglichkeit, polymorphe Zuordnungen zu implementieren, da ein bestimmter Fremdschlüssel nur auf eine Zieltabelle verweisen kann.
Eine andere Lösung besteht darin, eine gemeinsame "Supertabelle" zu erstellen, die beide users
verwenden und schools
Referenzen, und verwenden Sie diese dann als übergeordnetes Element von sets
.
create table set_owner
create table users
PK is also FK --> set_owner
create table schools
PK is also FK --> set_owner
create table sets
FK --> set_owner
Sie können sich das analog zu einer Schnittstelle vorstellen in der OO-Modellierung:
interface SetOwner { ... }
class User implements SetOwner { ... }
class School implements SetOwner { ... }
class Set {
SetOwner owner;
}
Zu Ihren Kommentaren:
Lassen Sie die SetOwners-Tabelle ID-Werte generieren. Sie müssen in SetOwners einfügen, bevor Sie in Benutzer oder Schulen einfügen können. Machen Sie also die IDs in Benutzer und Schulen nicht automatisch inkrementierend; Verwenden Sie einfach den Wert, der von SetOwners generiert wurde:
INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');
Auf diese Weise wird kein bestimmter ID-Wert sowohl für eine Schule als auch für einen Benutzer verwendet.
Sie können dies sicherlich tun. Tatsächlich kann es andere Spalten geben, die sowohl Benutzern als auch Schulen gemeinsam sind, und Sie könnten diese Spalten in die übergeordnete Tabelle SetOwners einfügen. Dies gelangt in Martin Fowlers Klassentabellenvererbung Muster.
Sie müssen eine Verbindung herstellen. Wenn Sie eine Abfrage von einem bestimmten Set aus durchführen und wissen, dass es einem Benutzer (nicht einer Schule) gehört, können Sie den Beitritt zu SetOwners überspringen und direkt Benutzern beitreten. Verknüpfungen müssen nicht unbedingt über Fremdschlüssel erfolgen.
SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...
Wenn Sie nicht wissen, ob ein bestimmter Satz zu einem Benutzer oder einer Schule gehört, müssen Sie eine äußere Verknüpfung mit beiden erstellen:
SELECT COALESCE(u.name, sc.name) AS name
FROM Sets s
LEFT OUTER JOIN Users u ON s.SetOwner_id = u.id
LEFT OUTER JOIN Schools sc ON s.SetOwner_id = sc.id
WHERE ...
Sie wissen, dass die SetOwner_id mit der einen oder anderen Tabelle übereinstimmen muss, Benutzer oder Schulen, aber nicht mit beiden.