Cara lain (tanpa Nulls dan tanpa siklus dalam FOREIGN KEY
hubungan) adalah memiliki meja ketiga untuk menyimpan "anak-anak favorit". Di sebagian besar DBMS, Anda membutuhkan UNIQUE
batasan tambahan TableB
.
@ Harun lebih cepat untuk mengidentifikasi bahwa konvensi penamaan di atas agak rumit dan dapat menyebabkan kesalahan. Biasanya lebih baik (dan akan membuat Anda tetap waras) jika Anda tidak memiliki Id
kolom di seluruh tabel Anda dan jika kolom (yang digabungkan) memiliki nama yang sama di banyak tabel yang muncul. Jadi, inilah penggantian nama:
Parent
ParentID INT NOT NULL PRIMARY KEY
Child
ChildID INT NOT NULL PRIMARY KEY
ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
UNIQUE (ParentID, ChildID)
FavoriteChild
ParentID INT NOT NULL PRIMARY KEY
ChildID INT NOT NULL
FOREIGN KEY (ParentID, ChildID)
REFERENCES Child (ParentID, ChildID)
Di SQL-Server (yang Anda gunakan), Anda juga memiliki opsi IsFavorite
kolom bit yang Anda sebutkan. Anak favorit unik per orang tua dapat dicapai melalui Indeks Unik yang difilter:
Parent
ParentID INT NOT NULL PRIMARY KEY
Child
ChildID INT NOT NULL PRIMARY KEY
ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID)
IsFavorite BIT NOT NULL
CREATE UNIQUE INDEX is_FavoriteChild
ON Child (ParentID)
WHERE IsFavorite = 1 ;
Dan alasan utama bahwa opsi 1 Anda tidak disarankan, setidaknya tidak dalam SQL-Server, adalah bahwa pola jalur melingkar dalam referensi kunci asing memiliki beberapa masalah.
Baca artikel yang cukup lama: SQL By Design: The Circular Reference
Saat memasukkan atau menghapus baris dari dua tabel, Anda akan mengalami masalah "ayam-dan-telur". Tabel mana yang harus saya masukkan terlebih dahulu - tanpa melanggar batasan apa pun?
Untuk mengatasinya, Anda harus mendefinisikan setidaknya satu kolom nullable. (OK, secara teknis Anda tidak perlu, Anda dapat memiliki semua kolom sebagai NOT NULL
tetapi hanya dalam DBMS, seperti Postgres dan Oracle, yang telah menerapkan batasan yang dapat ditangguhkan. Lihat jawaban @ Erwin dalam pertanyaan yang serupa: Kendala kunci asing kompleks di SQLAlchemy tentang cara ini bisa dilakukan di Postgres). Tetap saja, pengaturan ini terasa seperti berseluncur es tipis.
Periksa juga pertanyaan yang hampir sama pada SO (tetapi untuk MySQL) Dalam SQL, apakah boleh untuk dua tabel untuk merujuk satu sama lain? di mana jawaban saya hampir sama. MySQL tidak memiliki indeks parsial, sehingga satu-satunya pilihan yang layak adalah FK nullable dan solusi tabel tambahan.