Mysql
 sql >> Database >  >> RDS >> Mysql

Come usare chiavi esterne con PHP

Disambiguazione vincoli/colonne chiave esterna

Supponendo che tu ti riferisca ai vincoli della chiave esterna , la risposta breve sarebbe semplicemente non li usi .

Ed ecco che arriva quello lungo:

Siamo abituati a fare riferimento a le colonne sono chiavi esterne ad altri tavoli. Soprattutto durante il processo di normalizzazione, frasi come "user_purchase.i_id è una chiave esterna per gli items tabella" sarebbe molto comune. Anche se questo è un modo perfettamente valido per descrivere la relazione, può diventare un po' confuso quando raggiungiamo la fase di implementazione.

Supponi di aver creato le tue tabelle senza la FOREIGN KEY clausole:

CREATE TABLE user(
  id INT(11) NOT NULL AUTO_INCREMENT,
  username VARCHAR(50) NOT NULL,
  password VARCHAR(20) NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE items(
  i_id INT(11) NOT NULL AUTO_INCREMENT,
  name TINYTEXT NOT NULL,
  price DECIMAL(8,2) NOT NULL,
  PRIMARY KEY (i_id)
);

CREATE TABLE user_purchase(
  i_id INT(11) NOT NULL,
  name TINYTEXT NOT NULL,
  id INT(11) NOT NULL,
);

Si noti che, dal punto di vista delle relazioni, la chiave esterna colonne sono ancora implementati . C'è una colonna che fa riferimento all'user tabella (id ) e un altro che fa riferimento agli items tabella (i_id ) -- mettiamo il name colonna a parte per un momento. Considera i seguenti dati:

  user              user_purchase    items
| id  username |    | id  i_id |    | i_id  name            price |
| 23  john     |    | 55   10  |    |  10   chocolate bar    3.42 |
| 55  mary     |    | 70   10  |    |  33   mobile phone    82.11 |
| 70  fred     |    | 70   33  |    |  54   toothpaste       8.67 |
                    | 55   10  |    |  26   toy car          6.00 |
                    | 70   26  |

La relazione c'è. È implementato tramite user_purchase tabella, che contiene informazioni su chi ha acquistato cosa . Se dovessimo interrogare il database per un rapporto pertinente, faremmo:

select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)

Ed è così che usiamo la relazione e la chiave esterna colonne coinvolti.

E se lo facessimo:

insert into user_purchase (id,i_id) values (23,99)

Apparentemente, questa è una voce non valida. Sebbene sia presente un utente con id=23 , non ci sono articoli con i_id=99 . L'RDBMS permetterebbe che ciò avvenga, perché non sa di meglio . Ancora.

Ecco dove i vincoli della chiave esterna entrare in gioco. Specificando FOREIGN KEY (i_id) REFERENCES items(i_id) nel user_purchase definizione della tabella, diamo essenzialmente all'RDBMS una regola da seguire:voci con i_id valori che non sono contenuti in items.i_id colonna non sono accettabili . In altre parole, mentre è una chiave esterna colonna implementa il riferimento , una chiave esterna vincolo applica l'integrità referenziale .

Nota, tuttavia, che quanto sopra select non cambierebbe, solo perché hai definito un vincolo FK. Pertanto, tu non utilizzare vincoli FK, lo fa RDBMS, per proteggere i tuoi dati.

Esuberi

Chiediti:perché lo vorresti? Se le due chiavi esterne devono servire allo stesso scopo, la ridondanza alla fine ti metterà nei guai. Considera i seguenti dati:

 user_purchase                   items
| id  i_id  name           |    | i_id  name            price |
| 55   10   chocolate bar  |    |  10   chocolate bar    3.42 |
| 70   10   chocolate bar  |    |  33   mobile phone    82.11 |
| 70   33   mobile phone   |    |  54   toothpaste       8.67 |
| 55   10   toothpaste     |    |  26   toy car          6.00 |
| 70   26   toy car        |

Cosa c'è di sbagliato in questa immagine? Ha fatto l'utente 55 comprare due barrette di cioccolato o una barretta di cioccolato e un dentifricio? Questo tipo di ambiguità può comportare molti sforzi per mantenere i dati sincronizzati, il che non sarebbe necessario se mantenessimo solo una delle chiavi esterne. Infatti, perché non eliminare il name colonna del tutto, poiché è implicita nella relazione.

Ovviamente, potremmo risolverlo implementando una chiave esterna composita, impostando PRIMARY KEY(i_id,name) per gli items tabella (o definendo un extra UNIQUE(i_id,name) index, non importa) e poi impostando un FOREIGN KEY(i_id,name) REFERENCES items(i_id,name) . In questo modo, solo le coppie (i_id,name) che esistono negli items la tabella sarebbe valida per user_purchases . A parte il fatto che ne avresti ancora uno chiave esterna , questo approccio è del tutto superfluo, a condizione che i_id la colonna è già sufficiente per identificare un elemento (non posso dire lo stesso per il name colonna...).

Tuttavia, non esiste una regola contro l'utilizzo di più chiavi esterne in una tabella. In effetti, ci sono circostanze che richiedono un tale approccio. Considera una person(id,name) tabella e un parent(person,father,mother) uno, con i seguenti dati:

 person             parent
| id  name    |    | person  father  mother |
| 14  John    |    |   21      14      59   |
| 43  Jane    |    |   14      76      43   |
| 21  Mike    |
| 76  Frank   |
| 59  Mary    |

Ovviamente, tutte e tre le colonne del parent table sono chiavi esterne per person . Non per la stessa relazione , però, ma per tre diversi :Poiché anche i genitori di una persona sono persone, le due colonne corrispondenti devono fare riferimento alla stessa tabella person fa. Nota, tuttavia, che i tre campi non solo possono ma anche devono fare riferimento a person diverse s nello stesso parent fila, dal momento che nessuno è il suo stesso genitore e il padre di nessuno è anche sua madre.