Il progetto corrente è denominato archi esclusivi in cui la tabella sets
ha due chiavi esterne e ha bisogno esattamente di una di esse per essere non null. Questo è un modo per implementare le associazioni polimorfiche, poiché una determinata chiave esterna può fare riferimento a una sola tabella di destinazione.
Un'altra soluzione è quella di fare una comune "supertable" che entrambi users
e schools
riferimenti, e quindi utilizzare tale come il genitore di 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
Si può pensare a questo come analogo a un un'interfaccia in OO modellazione:
interface SetOwner { ... }
class User implements SetOwner { ... }
class School implements SetOwner { ... }
class Set {
SetOwner owner;
}
Re tuoi commenti:
Quindi la tabella SetOwner contiene sia UserIDs e SchoolIDs, corretto? Ciò significherebbe che non mi sarebbe permesso avere lo stesso ID per un utente e una scuola. Come posso far valere questo?
Lascia che la tabella SetOwners generi valori di identificazione. Devi inserire in SetOwners prima di poterlo inserire in Utenti o Scuole. Quindi inserisci ID in Utenti e scuole non autoincremento; basta usare il valore che è stato generato da SetOwners:
INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');
questo modo non dato valore id verrà utilizzata sia per una scuola e un utente.
Se mi piacerebbe ottenere il tipo proprietario per un set, ho bisogno di un attributo ownerType in mia tabella SetOwner?
Si può certamente fare questo. Di fatto, potrebbero esserci altre colonne comuni a utenti e scuole e potresti inserire queste colonne in SetOwners superabili. Questo entra nel pattern Class Table Inheritance di Martin Fowler.
E se voglio ottenere il nome della scuola o dell'utente (qualunque sia il tipo), posso farlo con una singola query, o ho bisogno di due query (prima di ottenere il tipo e il secondo per ottenere il nome)?
È necessario effettuare un join. Se stai interrogando da un determinato Set e sai che appartiene a un utente (non a una scuola) puoi saltare a unirsi a SetOwners e unirti direttamente agli Utenti. I join non devono necessariamente passare per le chiavi esterne.
SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...
Se non si sa se un dato insieme appartiene ad un utente oa una scuola, che avrebbe dovuto fare un outer join a entrambi:
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 ...
si sa che il SetOwner_id deve abbinare uno o l'altro tavolo, utenti o scuole, ma non entrambi.
Che cosa hai usato per creare la grafica? – basszero
@basszero: MySQL Workbench –
Eeeek !!! Ha fatto molta strada dall'ultima volta che l'ho provato! – basszero