Rozważ następujące:
entity User
{
autoincrement uid;
string(20) name;
int privilegeLevel;
}
entity DirectLoginUser
{
inherits User;
string(20) username;
string(16) passwordHash;
}
entity OpenIdUser
{
inherits User;
//Whatever attributes OpenID needs... I don't know; this is hypothetical
}
Różne rodzaje użytkowników (użytkownicy z bezpośrednim logowaniem i użytkownicy OpenID) wykazują zależność IS-A; mianowicie, że oba typy użytkowników są użytkownikami. Istnieje kilka sposobów przedstawienia tego w RDBMS:
Way One
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
username VARCHAR(20) NULL,
passwordHash VARCHAR(20) NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Sposób drugi
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privilegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE DirectLogins
(
uid INTEGER NOT_NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
CREATE TABLE OpenIDLogins
(
uid INTEGER NOT_NULL,
// ...
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
Sposób trzeci
CREATE TABLE DirectLoginUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE OpenIDUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Jestem prawie pewien, że trzeci sposób jest niewłaściwy, ponieważ nie można wykonać prostego łączenia przeciwko użytkownikom w innym miejscu w bazie danych.
Mój przykład z prawdziwego świata nie jest jednak przykładem użytkowników z różnymi loginami; Interesuje mnie, jak modelować ten związek w ogólnym przypadku.
database-design
Billy ONeal
źródło
źródło
Odpowiedzi:
Drugi sposób to właściwy sposób.
Twoja klasa podstawowa otrzymuje tabelę, a następnie klasy potomne otrzymują własne tabele z tylko dodatkowymi polami, które wprowadzają, a także odniesienia do klucza obcego do tabeli podstawowej.
Jak sugerował Joel w swoich komentarzach do tej odpowiedzi, możesz zagwarantować, że użytkownik będzie miał albo login bezpośredni, albo login OpenID, ale nie jedno i drugie (i być może żadne), dodając kolumnę typu do każdej tabeli podtypu, która zwraca klucze do tabeli głównej. Kolumna typu w każdej tabeli podtypu jest ograniczona do posiadania pojedynczej wartości reprezentującej typ tej tabeli. Ponieważ ta kolumna ma obcy klucz do tabeli głównej, tylko jeden wiersz podtypu może jednocześnie łączyć się z tym samym wierszem głównym.
Na przykład DDL MySQL wyglądałby mniej więcej tak:
(Na innych platformach
CHECK
zamiast tego użyłbyś ograniczeniaENUM
). MySQL obsługuje złożone klucze obce, więc powinno to działać dla Ciebie.Sposób pierwszy jest prawidłowy, chociaż marnujesz miejsce w tych
NULL
możliwych kolumnach, ponieważ ich użycie zależy od typu użytkownika. Zaletą jest to, że jeśli zdecydujesz się rozwinąć typy typów użytkowników do przechowywania, a typy te nie wymagają dodatkowych kolumn, możesz po prostu rozwinąć domenęENUM
i użyć tej samej tabeli.Sposób trzy wymusza wszelkie zapytania, które odsyłają do użytkowników, do sprawdzenia obu tabel. Zapobiega to także odwoływaniu się do tabeli pojedynczych użytkowników za pomocą klucza obcego.
źródło
UNION
, albo bym sugerował indeksowany widok z unikalnym indeksem przeciwUNION ALL
stanowiuid
od dwóch tabelach.)type
kolumnę do każdej tabeli podtypu, która jest ograniczona przezCHECK
ograniczenie, aby mieć dokładnie jedną wartość (typ tej tabeli). Następnie przekształcamy klucze obce tabeli podrzędnej do super-tabeli w klucze złożone na obuuid
itype
. To genialne.Zostałyby nazwane
i wszystkie mają swoje legalne zastosowania i są obsługiwane przez niektóre biblioteki. Musisz dowiedzieć się, który najlepiej pasuje.
Posiadanie wielu tabel znacznie zwiększy zarządzanie danymi do kodu aplikacji, ale zmniejszy ilość nieużywanego miejsca.
źródło