Nej, det är inte okej. Cirkulära referenser mellan tabeller är röriga. Se denna (decennium gammal) artikel:SQL By Design:The Circular Reference
Vissa DBMS kan hantera dessa, och med särskild försiktighet, men MySQL kommer att ha problem.
Alternativ 1
Som din design, för att göra en av de två FK:erna nullbar. Detta gör att du kan lösa problemet med kyckling och ägg (vilken tabell ska jag lägga in i först?).
Det finns dock ett problem med din kod. Det kommer att tillåta en produkt att ha en standardbild där den bilden kommer att referera till en annan produkt!
För att inte tillåta ett sådant fel bör din FK-begränsning vara:
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
Detta kräver en UNIQUE
constraint/index i tabellen products_pictures
på (product_id, id)
för att ovanstående FK ska definieras och fungera korrekt.
Alternativ 2
En annan metod är att ta bort Default_Picture_ID
kolumnen från product
tabell och lägg till en IsDefault BIT
kolumnen i picture
tabell. Problemet med den här lösningen är hur man tillåter att endast en bild per produkt har den biten på och alla andra att ha den av. I SQL-Server (och jag tror i Postgres) kan detta göras med ett partiellt index:
CREATE UNIQUE INDEX is_DefaultPicture
ON products_pictures (Product_ID)
WHERE IsDefault = 1 ;
Men MySQL har ingen sådan funktion.
Alternativ 3
Detta tillvägagångssätt låter dig även ha båda FK-kolumnerna definierade som NOT NULL
är att använda uppskjutningsbara begränsningar. Detta fungerar i PostgreSQL och jag tror i Oracle. Kontrollera denna fråga och svaret av @Erwin:Komplex främmande nyckel-begränsning i SQLAlchemy
(Alla nyckelkolumnerna INTE NULL del).
Begränsningar i MySQL kan inte skjutas upp.
Alternativ 4
Metoden (som jag tycker är renast) är att ta bort Default_Picture_ID
kolumn och lägg till ytterligare en tabell. Ingen cirkulär bana i FK-begränsningarna och alla FK-kolumner kommer att vara NOT NULL
med den här lösningen:
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)
Detta kräver också en UNIQUE
constraint/index i tabellen products_pictures
på (product_id, id)
som i lösning 1.
För att sammanfatta, med MySQL har du två alternativ:
-
alternativ 1 (en nollbar FK-kolumn) med korrigeringen ovan för att upprätthålla integritet korrekt
-
alternativ 4 (inga nollbara FK-kolumner)