Nej, det er ikke i orden. Cirkulære referencer mellem tabeller er rodet. Se denne (årti gamle) artikel:SQL By Design:The Circular Reference
Nogle DBMS kan håndtere disse, og med særlig omhu, men MySQL vil have problemer.
Mulighed 1
Som dit design, at gøre en af de to FK'er nullbar. Dette giver dig mulighed for at løse kylling-og-æg-problemet (hvilken tabel skal jeg først indsætte i?).
Der er dog et problem med din kode. Det vil tillade et produkt at have et standardbillede, hvor billedet vil referere til et andet produkt!
For at afvise en sådan fejl skal din FK-begrænsning være:
CONSTRAINT FK_products_1
FOREIGN KEY (id, default_picture_id)
REFERENCES products_pictures (product_id, id)
ON DELETE RESTRICT --- the SET NULL options would
ON UPDATE RESTRICT --- lead to other issues
Dette kræver en UNIQUE
constraint/index i tabel products_pictures
på (product_id, id)
for at ovenstående FK defineres og fungerer korrekt.
Mulighed 2
En anden fremgangsmåde er at fjerne Default_Picture_ID
kolonne fra product
tabel og tilføj en IsDefault BIT
kolonne i picture
bord. Problemet med denne løsning er, hvordan man kun tillader et billede pr. produkt at have den bit på og alle andre at have det slukket. I SQL-Server (og jeg tror i Postgres) kan dette gøres med et delvist indeks:
CREATE UNIQUE INDEX is_DefaultPicture
ON products_pictures (Product_ID)
WHERE IsDefault = 1 ;
Men MySQL har ingen sådan funktion.
Mulighed 3
Denne tilgang tillader dig endda at have begge FK-kolonner defineret som NOT NULL
er at bruge udskydbare begrænsninger. Dette virker i PostgreSQL, og jeg tror i Oracle. Tjek dette spørgsmål og svaret af @Erwin:Kompleks fremmednøglebegrænsning i SQLAlchemy
(Alle nøglekolonner IKKE NULL del).
Begrænsninger i MySQL kan ikke udskydes.
Mulighed 4
Fremgangsmåden (som jeg finder den reneste) er at fjerne Default_Picture_ID
kolonne og tilføje endnu en tabel. Ingen cirkulær sti i FK-begrænsningerne, og alle FK-kolonner vil være NOT NULL
med denne løsning:
product_default_picture
----------------------
product_id NOT NULL
default_picture_id NOT NULL
PRIMARY KEY (product_id)
FOREIGN KEY (product_id, default_picture_id)
REFERENCES products_pictures (product_id, id)
Dette kræver også en UNIQUE
constraint/index i tabel products_pictures
på (product_id, id)
som i løsning 1.
For at opsummere, med MySQL har du to muligheder:
-
mulighed 1 (en nullbar FK-kolonne) med rettelsen ovenfor for at håndhæve integriteten korrekt
-
mulighed 4 (ingen nullbare FK-kolonner)