Le relazioni uno-a-molti sono una delle relazioni di database più comuni. Se vuoi imparare quando e come usare le relazioni uno-a-molti, allora questo articolo è un ottimo punto di partenza.
Utilizzerai sicuramente le relazioni uno-a-molti per archiviare informazioni in qualsiasi database relazionale, sia che tu stia progettando software di livello aziendale o semplicemente creando un semplice database per tenere traccia della collezione di francobolli di tuo zio.
Una breve introduzione al modello relazionale
I database relazionali sono un componente fondamentale di qualsiasi applicazione transazionale moderna. Il modello relazionale è composto da tabelle (dati organizzati in righe e colonne) che hanno almeno una chiave univoca che identifica ogni riga. Ogni tabella rappresenta un'entità. Questo è mostrato nell'esempio seguente, una versione molto semplice di una tabella che rappresenta gli ordini dei clienti:
Il diagramma sopra, che ho creato online utilizzando Vertabelo, ha un'unica tabella. Ogni riga della tabella rappresenta un ordine e ogni colonna (nota anche come attributo ) rappresenta ogni singola informazione contenuta in un ordine.
Per coloro che non hanno ancora familiarità con lo strumento di progettazione Vertabelo, l'articolo Quali sono i simboli utilizzati nei diagrammi ER? spiega i simboli e le convenzioni utilizzate. Potresti anche voler saperne di più sui modelli relazionali e sui database utilizzando il nostro corso di modellazione di database.
Cosa sono le relazioni e perché ne abbiamo bisogno?
Se diamo uno sguardo più approfondito alla tabella utilizzata nell'esempio precedente, vedremo che in realtà non rappresenta un ordine completo. Non ha tutte le informazioni che ti aspetteresti che avesse. Noterai che non include alcun dato relativo al cliente che ha effettuato l'ordine, né ha nulla in merito ai prodotti o servizi ordinati.
Cosa dobbiamo fare per completare questo design per memorizzare i dati dell'ordine? Dovremmo aggiungere informazioni su clienti e prodotti all'Ordine tavolo? Ciò richiederebbe l'aggiunta di nuove colonne (attributi) per nomi di clienti, codici fiscali, indirizzi e così via, come mostrato di seguito:
"ID ordine" | "Data dell'ordine" | "Importo dell'ordine" | Cliente | "Indirizzo cliente" | "Telefono Cliente" | "Codice fiscale" |
---|---|---|---|---|---|---|
1 | 23 giugno | $ 10 248,15 | International Services Ltd | 1247 St River Blvd, Charlotte, NC | (555) 478-8741 | IS789456 |
2 | 27 giugno | $ 14 785,45 | World Master Importing Inc. | 354 Mountain Hill Road, Los Angeles, California | (555) 774-8888 | WM321456 |
3 | 01 luglio | $7 975,00 | First State Provisioning Llc | 444 North Highway, Houston, TX | (555) 698-7411 | FS947561 |
4 | 03 luglio | $ 6 784,25 | International Services Ltd | 1247 St River Blvd, Charlotte, NC | (555) 478-8741 | IS789456 |
5 | luglio-07 | $ 21 476,10 | World Master Importing Inc. | 354 Mountain Hill Road, Los Angeles, California | (555) 774-8888 | WM321456 |
6 | lug-12 | $9 734,00 | First State Provisioning Llc | 444 North Highway, Houston, TX | (555) 698-7411 | FS947561 |
7 | luglio-17 | $ 14 747,45 | World Master Importing Inc. | 354 Mountain Hill Road, Los Angeles, California | (555) 774-8888 | WM321456 |
8 | 21 luglio | $ 19 674,85 | International Services Ltd | 1247 St River Blvd, Charlotte, NC | (555) 478-8741 | IS789456 |
Se lo facciamo, incontreremo presto dei problemi. La maggior parte dei clienti effettua più di un ordine, quindi questo sistema memorizzerà le informazioni sui clienti molte volte, una per ogni ordine di ciascun cliente. Non sembra una mossa intelligente.
Inoltre, cosa succede quando un cliente cambia numero di telefono? Se qualcuno ha bisogno di chiamare il cliente, potrebbe trovare il vecchio numero negli ordini precedenti, a meno che qualcuno non aggiorni centinaia (o addirittura migliaia) di ordini esistenti con le nuove informazioni. E lo stesso varrebbe per qualsiasi altra modifica.
Un modello relazionale richiede di definire ogni entità come una tabella separata e di stabilire relazioni tra di loro. La memorizzazione di tutte le informazioni in un'unica tabella non funziona.
Esistono diversi tipi di relazioni tra le tabelle, ma probabilmente la più comune è la relazione uno-a-molti, spesso scritta come 1:N. Questo tipo di relazione significa che una riga in una tabella (di solito chiamata tabella padre) può avere una relazione con molte righe in un'altra tabella (di solito chiamata tabella figlio). Alcuni esempi comuni di relazioni uno-a-molti sono:
- Una casa automobilistica produce molti modelli diversi, ma un particolare modello di auto viene costruito solo da una sola casa automobilistica.
- Un cliente può effettuare più acquisti, ma ogni acquisto viene effettuato da un solo cliente.
- Un'azienda può avere molti numeri di telefono, ma un numero di telefono appartiene a un'azienda.
Esistono anche altri tipi di relazioni tra tabelle; se vuoi saperne di più su di loro, consulta questo articolo sulle relazioni molti-a-molti.
Tornando al nostro esempio di ordine iniziale, il Customer
table sarebbe la tabella padre e l'Order
tavola il bambino; un cliente può avere più ordini, mentre un ordine può appartenere a un solo cliente.
Si noti che la definizione uno-a-molti consente di associare una riga nella tabella padre a più righe in ogni tabella figlio, ma non la richiede. In realtà, il design consente a un cliente di avere zero ordini (ovvero un nuovo cliente che non ha ancora effettuato il primo acquisto), un ordine (un cliente relativamente nuovo che ha effettuato un unico acquisto) o molti ordini (un cliente abituale).
Mostrare le relazioni uno-a-molti in un diagramma ER
Diamo un'occhiata a un esempio più completo di un semplice sistema di ordinazione dei clienti che utilizza un diagramma ER (o relazione di entità). (Se vuoi saperne di più su questi diagrammi, Vertabelo Features:Logical Diagrams è un ottimo punto di partenza.) Ecco il modello:
Questo è un design più realistico. Noterai che ci sono nuove entità (tabelle) nel diagramma, che ora contiene le tabelle Customer
, Order
, Order Detail
e Product
. Tuttavia, la cosa più importante che noti è che ora ci sono relazioni tra i tavoli .
In un modello di database, le relazioni sono rappresentate da linee che collegano due entità. Le caratteristiche di queste relazioni sono rappresentate da diversi connettori:
- Quando è presente un'unica linea verticale, l'entità più vicina a quel connettore ha solo una riga interessata dalla relazione. È l'uno in uno-a-molti.
- Quando c'è un connettore multilinea che assomiglia a una zampa di gallina, l'entità più vicina a quel connettore ha più righe interessate dalla relazione; sono i "molti".
Osservando l'immagine e conoscendo la notazione, è semplice capire che il diagramma definisce che ogni Order
può avere molti Order Detail
e che ogni Order Detail
appartiene a un unico Order
.
Implementazione di una relazione uno-a-molti tra le tabelle
Per definire una relazione uno-a-molti tra due tabelle, la tabella figlio deve fare riferimento a una riga nella tabella padre. I passaggi necessari per definirlo sono:
- Aggiungi una colonna alla tabella figlio che memorizzerà il valore dell'identificatore primario. (In realtà, la maggior parte dei motori di database consente che sia qualsiasi chiave univoca dalla tabella padre, non solo la chiave primaria.) La colonna può essere definita come obbligatoria a seconda delle esigenze aziendali; anche così, di solito vengono create colonne di chiavi esterne
Nota: È buona norma mantenere il nome delle colonne di riferimento uguale a quello della tabella (principale) di riferimento. Questo rende ancora più semplice capire la relazione.
- Aggiungi una chiave straniera vincolo sulla tabella figlio. Ciò indica che ogni valore archiviato in questa nuova colonna fa riferimento a una riga nella tabella padre.
I vincoli di chiave esterna sono una funzionalità disponibile sul database relazionale che impone che:
- Quando aggiungi una riga alla tabella figlio, il valore della colonna di riferimento deve corrispondere a uno (e solo uno) nella tabella padre. (Ecco perché è necessario fare riferimento a una colonna o a un insieme di colonne che costituiscono una chiave primaria o una chiave univoca).
- Se qualcuno tenta di eliminare una riga dalla tabella padre o tenta di modificare i valori della chiave univoca/primaria utilizzata come riferimento e c'è una tabella figlio che fa riferimento a quella riga, l'operazione avrà esito negativo.
Queste due caratteristiche garantiscono che il database mantenga la sua integrità. Non c'è possibilità di creare ordini che facciano riferimento a un cliente inesistente, né di eliminare un cliente che ha già ordini.
Creazione di una chiave esterna
La sintassi della chiave esterna in genere dipende dal motore di database di destinazione. Una volta definito il modello logico, è possibile utilizzare la funzione "Genera modello fisico..." sui diagrammi logici di Vertabelo per trasformare il modello (agnostico del database) in un modello fisico che corrisponde al provider del database. Vertabelo genererà anche lo script SQL richiesto che ti consentirà di creare le tabelle e le relazioni nel database di destinazione.
Alcuni esempi pratici di relazioni 1:N
Ora esaminiamo alcuni esempi di relazioni uno-a-molti nel mondo reale.
Relazione uno-a-molti utilizzando le chiavi primarie
Questo è probabilmente lo scenario più comune quando si definisce una relazione uno-a-molti. La tabella figlio utilizza il valore della chiave primaria della tabella padre per stabilire la relazione.
Questo esempio descrive un servizio di streaming online di base. Esaminiamo cosa è memorizzato in ciascuna delle tabelle e come si relazionano con le altre tabelle nel nostro modello:
- Ogni
ServiceType
definisce come "comporta" un account (ad es. quanti utenti possono connettersi al sistema contemporaneamente, se l'account ha il Full HD abilitato, ecc.). Ha una relazione con altre entità:- Una relazione uno-a-molti con
Account
, il che significa che ogni tipo di servizio può avere molti account di quel tipo.
- Una relazione uno-a-molti con
- Ogni
Account
memorizza le informazioni su un cliente. Ha due relazioni dirette con altre entità:- Ogni account appartiene a un unico
ServiceType
, come spiegato sopra. - Questa tabella ha una relazione uno-a-molti con il
Profile
tabella, il che significa che più di un utente può connettersi al nostro sistema utilizzando lo stesso account.
- Ogni account appartiene a un unico
- Ogni
Profile
rappresenta un utente nel nostro sistema. Ha due relazioni con altre entità:- Ogni profilo appartiene a un unico
Account
. Ciò consente a tutti i membri della famiglia (o forse a un gruppo di amici) di condividere lo stesso account mentre ognuno ha i propri attributi personali (ad es. il nome di un profilo). - Ogni profilo ha un
Avatar
univoco .
- Ogni profilo appartiene a un unico
- Ogni
Avatar
è un'immagine che ci permette di identificare velocemente ogni account utente. Ha una relazione con un'altra entità:- Una relazione uno-a-molti con
Profile
, il che significa che un singolo avatar può essere assegnato a profili su account diversi.
- Una relazione uno-a-molti con
Relazioni uno-a-molti con chiavi univoche naturali o surrogate
L'uso di chiavi primarie surrogate è un modo ampiamente accettato di modellare le tabelle. (Le chiavi primarie surrogate sono generate dal database e non hanno alcun valore commerciale effettivo.) Questo metodo produce chiavi più semplici da usare e aggiunge una certa flessibilità per quando sono necessarie modifiche.
Tuttavia, ci sono situazioni, ad es. quando abbiamo bisogno di interagire con sistemi esterni, dove l'utilizzo di una chiave generata nel nostro database è un approccio sbagliato. Per questi scenari, di solito è meglio utilizzare chiavi naturali, che sono valori univoci che fanno parte dell'entità archiviata e non vengono generati automaticamente dal nostro database.
L'esempio seguente rappresenta un modello di dati di base di un'organizzazione che tiene traccia dei veicoli (ovvero marca, modello, colore e anno dell'auto), dei loro proprietari e di eventuali infrazioni di transito associate. Quando l'abbiamo definita, abbiamo utilizzato chiavi primarie surrogate per stabilire le relazioni tra veicoli e marche, modelli e proprietari, poiché tutte queste informazioni sono gestite internamente dal nostro sistema.
In questo sistema, come può un agente di polizia in un'altra città segnalare un'auto parcheggiata illegalmente utilizzando la nostra chiave primaria del veicolo (VehicleID
)? Tali informazioni non sono naturalmente disponibili sul veicolo parcheggiato, ma la targa c'è. Ciò significa che il modo più semplice per ricevere e associare informazioni da una fonte esterna (in questo esempio, qualsiasi dipartimento di polizia del paese) consiste nell'utilizzare una chiave univoca naturale anziché una chiave primaria surrogata.
L'implementazione fisica di questo diagramma logico per SQL Server è disponibile qui:
Relazioni uno-a-molti sullo stesso tavolo
Gli esempi precedenti erano incentrati sulle relazioni tra due o più tabelle, ma esistono anche scenari in cui la relazione si verifica tra righe della stessa tabella. Questo tipo di relazione uno-a-molti è anche chiamata relazione gerarchica; è utilizzato in molti sistemi per rappresentare strutture ad albero, ad esempio un organigramma, un conto di contabilità generale o un prodotto e le sue parti componenti.
La prima volta che devi creare questo tipo di struttura, sarai tentato di definire una tabella per ciascuno dei livelli della tua gerarchia, come mostrato nel diagramma seguente:
Ci sono molti problemi in questo approccio:
- Tutte le tabelle sono quasi identiche e memorizzano informazioni identiche.
- Se la tua organizzazione aggiunge un nuovo livello, dovrai modificare il modello dati e aggiungere una nuova tabella, nuove chiavi esterne, ecc.
- Se un dipendente riceve una promozione, è necessario eliminarlo da una tabella e inserirlo in un'altra.
Pertanto, il modo migliore per modellare questo tipo di struttura è utilizzare un'unica tabella che faccia riferimento a se stessa, come mostrato in questo diagramma:
Qui vediamo un singolo Employee
tabella e una colonna denominata EmployeeID_Manager
. Quella colonna fa riferimento a un altro dipendente della stessa organizzazione che è il supervisore/responsabile dell'attuale dipendente.
Ho aggiunto il _Manager
suffisso per distinguere tra l'ID della riga corrente e l'ID del manager. (Potremmo usare ManagerID
invece, ma preferisco mantenere il nome originale della colonna di riferimento e, nei casi in cui entrambe si trovano nella stessa tabella, aggiungere un suffisso che spieghi il ruolo che effettivamente ha).
Comprendere le relazioni gerarchiche è più complesso di altre relazioni uno-a-molti. Ma se ti dimentichi della tabella in cui sono memorizzate tutte le informazioni e immagini che in realtà ci siano tabelle diverse, ognuna delle quali rappresenta un livello nella gerarchia, è un po' più facile da visualizzare. Immagina di creare la relazione tra due entità e poi combinarle in un'unica entità.
Cosa c'è dopo?
Gli esempi forniti ti aiuteranno a identificare diversi scenari che richiedono una relazione uno-a-molti. Puoi iniziare a progettare la tua struttura di database utilizzando Vertabelo Database Modeler, uno strumento basato sul Web che ti consente non solo di generare un modello logico ma anche di crearne una versione fisica per il provider di database di cui hai bisogno.
Ora tocca a te:usa la sezione commenti per parlarci delle tue opinioni su questo articolo, porre ulteriori domande o condividere le tue esperienze di modellazione del database.