sql >> Databasteknik >  >> RDS >> Mysql

I SQL, är det OK att två tabeller refererar till varandra?

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(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(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)



  1. Hur man distribuerar PostgreSQL för hög tillgänglighet

  2. Vad kan få en Oracle ROWID att ändras?

  3. 2 sätt att lista alla funktioner i MySQL

  4. TIMESTAMPADD() Exempel – MySQL