Devo aggiungere chiavi esterne transitive?


11

Esempio semplice: esiste una tabella di clienti.

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

Tutti gli altri dati nel database devono essere collegati a un Customer, quindi ad esempio Ordersè simile al seguente:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

Supponiamo ora che ci sia una tabella che collega a Orders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

Devo aggiungere una chiave esterna separata da Itemsa Customers?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

Un'immagine invece: dovrei aggiungere la linea tratteggiata / FK?

Schema di esempio semplice


Modifica: ho aggiunto le definizioni delle chiavi primarie alle tabelle. Vorrei ripetere il punto che ho esposto sopra: il database è sostanzialmente messo a tacere dai clienti, come misura di correttezza / sicurezza. Pertanto, tutte le chiavi primarie contengono l' customerID.


2
No, non dovresti. Non è necessario l'FK extra. Il vincolo viene applicato dagli altri due FK.
ypercubeᵀᴹ

@ypercube Ci sono delle penalità prestazionali per avere un FK ridondante? Qualche vantaggio che potresti pensare? ...
Vektor,

1
@vektor, gli aspetti delle prestazioni probabilmente variano da un rdbms a un altro, ma in genere si ottiene un impatto sulle prestazioni per ogni nuovo FK aggiunto, poiché ogni inserimento / aggiornamento / eliminazione in una delle tabelle PK / FK deve essere verificato rispetto al vincolo. Con tabelle PK di grandi dimensioni, questa penalità può essere piuttosto severa.
Daniel Hutmacher,

Risposte:


6

Penso che questa sia l'idea originale.

inserisci qui la descrizione dell'immagine

La prima cosa da notare è che il PK sulla tabella LineItem ha tre attributi {CustomerID, CustomerOrderNo, OdrerItemNo}, a differenza di solo due nel tuo esempio.

La seconda cosa da notare è la confusione derivante dall'uso del idnome generico per un attributo.

Il CustomerOrderNodovrebbe essere idealmente (1,2,3 ..) per ogni cliente e OrderItemNo(1,2,3 ...) per ogni ordine.

Bene, questo è bello se possibile, ma richiede una query alla ricerca del valore massimo precedente, come

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

che spesso non è preferito negli ambienti ad alto volume di transazioni, quindi è comune vederli sostituiti da un auto-incremento, essenzialmente per lo stesso scopo. È vero che questo auto-incremet è ora unico, quindi può essere usato come un CHIAVE - ma puoi scegliere di vederlo come un compromesso necessario per il OrderItemNo.

Quindi, con qualche ridenominazione CustomerOrderNo -> OrderNoe OrderItemNo-> ItemNopotresti arrivare a questo modello

inserisci qui la descrizione dell'immagine

Quindi ora se guardi Orderquanto segue sono unici

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

Si noti che {CustomerID, OrderNo}viene propagato in modo LineItemche funga da FK.

Se strizzi gli occhi un po ', questo è vicino al tuo esempio, ma con PKs {ItemNo} and {OrderNo}solo - al contrario di due colonne PK dal tuo esempio.

Ora la domanda è: perché non semplificare qualcosa del genere?

inserisci qui la descrizione dell'immagine

Che va bene, ma introduce PATH DIPENDENZA - non si può unire LineItemcon Customerdirettamente, necessario utilizzare Ordernel join.


Preferisco il primo caso, quando possibile: scegli il tuo preferito. E ovviamente, in questi tre casi non è necessario un FK diretto da LineItema Customer.


Ho cercato, ma non riesco a vedere "dipendenza dal percorso" come termine ampiamente adottato per ciò che definirei "relazione transitiva di secondo grado" (anche se la mia terminologia è probabilmente errata)
Dai

2

L '"articolo" non deve fare riferimento direttamente al "cliente", poiché ciò è implicito nell' "ordine" dell'articolo. Pertanto, non avrai assolutamente bisogno delle colonne "cliente" nella tabella "articoli".

La relazione dell'articolo con il cliente è assicurata con la chiave esterna esistente.

Se ordini.id è una colonna di identità, prendere in considerazione la rimozione completa di items.customer.


1
Grazie, non ho notato che anche "cliente" è stato incluso nel primo FK da "articoli" a "ordini". Ho elaborato la mia risposta di conseguenza.
Daniel Hutmacher,

@DanielHutmacher Ho modificato la domanda per contenere le chiavi primarie delle mie tabelle. Questo spiega gli strani FK che menzioni nella tua modifica.
Vektor,

Ok, ho aggiornato la mia risposta. :)
Daniel Hutmacher,

Immagino che avere customerin tutte le tabelle (e quindi silo il DB) sia un approccio insolito. Devo confessare che è solo qualcosa che ho visto nei miei lavori precedenti. Ha senso per te? Hai mai visto un tale design prima?
Vektor,

Direi che sembra un approccio datawarehouse (schema a stella), in cui si desidera denormalizzare intenzionalmente i dati per eliminare i join. Oppure la chiave primaria potrebbe essere composita, ovvero il primo, il secondo, il terzo ordine del cliente A, il primo, il secondo ordine del cliente B, ecc. Quando la colonna ID ordine da sola non è univoca.
Daniel Hutmacher,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.