Alcuni ottimi designer usano NULL nelle chiavi esterne senza conseguenze negative. Mi appoggio in quel modo io stesso. Un FK nullable rappresenta una relazione facoltativa. Nei casi in cui l'entità non ha alcuna relazione, l'FK contiene un NULL. Lo spazio in testa è minimo. Quando i join (equijoin, più precisamente) vengono eseguiti tra le due tabelle, le istanze contenenti NULL nell'FK verranno eliminate dal join, e questo è appropriato.
Detto questo, ti consiglierò un quarto metodo. Ciò comporta un totale di 4 tabelle, account, widget, tipi e custom_types. La tabella custom_types utilizza una tecnica chiamata Shared-primary-key, descritta di seguito.
CREATE TABLE accounts (
account_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
# Other Columns...,
PRIMARY KEY (account_id)
);
CREATE TABLE widgets (
widget_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
account_id INT UNSIGNED NOT NULL,
type_id INT UNSIGNED NOT NULL,
PRIMARY KEY (widget_id),
FOREIGN KEY (account_id) REFERENCES accounts(account_id) ON DELETE CASCADE,
FOREIGN KEY (type_id) REFERENCES types(type_id)
);
CREATE TABLE types (
type_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
account_id INT UNSIGNED NOT NULL,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (type_id),
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
CREATE TABLE custom_types (
type_id INT NOT NULL,
account_id INT UNSIGNED NOT NULL,
PRIMARY KEY (type_id),
FOREIGN KEY (type_id) REFERENCES types(type_id),
FOREIGN KEY (account_id) REFERENCES accounts(account_id)
);
La colonna type_id in custom_types è una chiave primaria condivisa. Si noti che è dichiarato SIA come chiave primaria che come chiave esterna e che non utilizza autonumber. È una copia della chiave primaria nei tipi per la voce corrispondente. La tabella dei tipi personalizzati contiene tutti i dati presenti nei tipi personalizzati ma assenti nei tipi preimpostati.
Per i tipi preimpostati, viene inserita una voce in tipi, ma nessuna voce viene inserita in tipi_personalizzati. Per custom_types, viene prima inserita una voce in tipi, quindi il valore risultante di type_id viene copiato in custom_types, insieme a account_id.
Se utilizzi tipi INNER JOIN e custom_type, i tipi preimpostati escono dal join. Se vuoi sia i tipi personalizzati che quelli preimpostati in un unico join, devi usare un LEFT JOIN o un RIGHT JOIN per ottenere quell'effetto. Si noti che il risultato di un LEFT o RIGHT JOIN conterrà alcuni NULL, anche se tali NULL non sono archiviati nel database.
Facendo clic su questa shared-primary-key ti fornirà una descrizione più dettagliata della tecnica della chiave primaria condivisa.