Desain Anda saat ini disebut busur eksklusif di mana sets
tabel memiliki dua kunci asing, dan membutuhkan salah satunya untuk menjadi non-null. Ini adalah salah satu cara untuk menerapkan asosiasi polimorfik, karena kunci asing yang diberikan hanya dapat mereferensikan satu tabel target.
Solusi lain adalah membuat "supertable" umum yang users
dan schools
referensi, dan kemudian gunakan itu sebagai induk dari 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
Anda dapat menganggap ini sebagai analog dengan antarmuka dalam pemodelan OO:
interface SetOwner { ... }
class User implements SetOwner { ... }
class School implements SetOwner { ... }
class Set {
SetOwner owner;
}
Komentar Anda:
Biarkan tabel SetOwners menghasilkan nilai id. Anda harus memasukkan ke dalam SetOwners sebelum Anda dapat memasukkan ke Pengguna atau Sekolah. Jadi buat id di Pengguna dan Sekolah bukan peningkatan otomatis; cukup gunakan nilai yang dihasilkan oleh SetOwners:
INSERT INTO SetOwners DEFAULT VALUES; -- generates an id
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location');
Dengan cara ini tidak ada nilai id yang akan digunakan untuk sekolah dan pengguna.
Anda pasti bisa melakukan ini. Sebenarnya, mungkin ada kolom lain yang umum untuk Pengguna dan Sekolah, dan Anda bisa meletakkan kolom ini di SetOwners supertable. Ini masuk ke Pewarisan Tabel Kelas Martin Fowler pola.
Anda perlu melakukan bergabung. Jika Anda menanyakan dari Set tertentu dan Anda tahu itu milik pengguna (bukan sekolah), Anda dapat melewati bergabung ke SetOwners dan bergabung langsung ke Pengguna. Bergabung tidak harus menggunakan kunci asing.
SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ...
Jika Anda tidak tahu apakah set tertentu milik Pengguna atau Sekolah, Anda harus melakukan gabungan luar untuk keduanya:
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 ...
Anda tahu bahwa SetOwner_id harus cocok dengan satu atau tabel lainnya, Pengguna atau Sekolah, tetapi tidak keduanya.