Table inheritance in PostgreSQL
Published: 2023-10-03 14:23:30

---
title: Table inheritance in PostgreSQL
published: true
date: 2023-05-25 00:00:00 UTC
tags: 
canonical_url: 
---

Il concetto di **ereditarietà** nella programmazione orientata agli oggetti è un qualcosa di piuttosto popolare: permette infatti di creare una relazione di dipendenza e gerarchia tra due entità, denominate -ad esempio- _genitore_ e_figlio_.

Questo vuol dire che, a partire dall’entità _genitore_, sarà possibile **ereditare** tutte le caratteristiche: attributi, tipo di dati e, nel caso della programmazione, anche le funzioni.

Come possiamo implementare la stessa logica all’interno di PostgreSQL?

Tramite il concetto di **table inheritance**.

# Definizione

L’_ereditarietà delle tabelle_ consente alle tabelle figlie di ereditare tutte le colonne della tabella genitore.

Una tabella figlia può ovviamente avere campi aggiuntivi oltre alle colonne ereditate, ma non richiede la ricreazione di queste da zero.

# Come funziona

Vediamo un esempio: la tabella _animals_ definisce un caso abbastanza generico di rappresentazione degli animali, con un ID, un nome e un’età:

```
CREATE TABLE animals(id serial, age int, name varchar(100))

```

A seguito, potremmo voler declinare gli animali nelle diverse specie che ci vengono in mente: _dogs_, ad esempio, i quali hanno una propria razza, ed eventualmente un microchip. In questo caso, nell’istruzione di creazione della tabella, utilizziamo la parola **inherits** , che stabilisce da quale tabella ereditare le colonne. In questo caso, da _animals:_

```
CREATE TABLE dogs(breed varchar(100), microchip boolean) inherits(animals)

```

Inseriamo degli animali all’interno della tabella principale e di quella figlia:

```
INSERT INTO animals(age, name) VALUES(3, 'Zoe');
INSERT INTO animals(age, name) VALUES(7, 'Zach');
INSERT INTO animals(age, name) VALUES(1, 'Zed');

INSERT INTO dogs(age, name, breed, microchip) VALUES(1, 'Dom', 'Bernese mountain dog', true);
INSERT INTO dogs(age, name, breed, microchip) VALUES(1, 'Jack', 'Jack Russell', true);

```

Se usi [pgAdmin](https://dev.to/scottw/pgadmin---postgresql-tools-5ejk) come client per accedere al tuo database, questo è quello che vedrai nel menù di sinistra: due frecce accanto alle tabelle, dove la tabella _animals_ riporta una freccia in uscita per indicare che ha delle tabelle che ereditano le sue proprietà, e al contrario _dogs_ ne ha una in entrata:

![](https://theredcode.it/img/postgres-table-inheritance-1.png)

# Elenco

Finora, nulla di eccezionale. Vediamo però come cambiano le cose quando si usa questa tipologia di rappresentazione, e proviamo ad elencare tutti i record presenti nella tabella “principale”:

```
SELECT id, age, name
 FROM public.animals;
>>>
id age name
1 3 "Zoe"
2 7 "Zach"
3 1 "Zed"
4 1 "Dom"
5 1 "Jack"

```

Vengono riportati 5 animali, e non 3, come quelli inseriti per la tabella _animals_: questo perché, di base, PostgreSQL andrà a restituire tutte le entità che afferiscono a quella tabella, comprese quelle “derivate”, come gli oggetti presenti in _dogs_.

Se volessimo però restringere il campo ai soli animali, potremmo usare un’istruzione speciale: **only**.

```
SELECT id, age, name
 FROM only public.animals;
>>>
id age name
1 3 "Zoe"
2 7 "Zach"
3 1 "Zed"

```

La parola chiave “only” può essere usata per indicare che la query deve essere applicata solo a una particolare tabella e non a qualsiasi altra tabella.

Notare un aspetto interessante: in PostgreSQL, quando si eredita una colonna che ha come tipo di dato _serial_ dalla tabella genitore, la sequenza è condivisa dalla tabella genitore e figlia.

Questo vuol dire che se inserissimo un nuovo animale nella tabella _dogs_, questo assumerebbe ID 7; se poi ne inserissimo uno nella tabella principale _animals_, questo avrebbe ID 8. Questo avviene anche per evitare che, nel rappresentare le diverse entità, gli ID delle due tabelle, vadano in conflitto.

# Modifica

Chiaramente, questo vuol dire che qualsiasi aggiornamento o cancellazione della tabella dei genitori non ha effetto solo sui record della tabella dei figli, ma anche su quella principale. Un esempio come il seguente risulta nella modifica di tutti i record presenti, compresi quelli presenti in _dogs_, del campo _age_ delle due tabelle:

```
UPDATE animals SET age=3

```

Per aggiornare solo i dati di una tabella, è sufficiente utilizzare l’operatore visto in precedenza:

```
UPDATE ONLY animals SET age=3

```

# Cascade

E se provassimo a cancellare la tabella _animals_? Questo sarebbe il risultato:

```
DROP TABLE animals;

```

![](https://theredcode.it/img/postgres-table-inheritance-2.png)

Questo perché il database tiene conto della relazione che c’è tra le tabelle e riporta che _dogs_ dipende da_animals_, pertanto non è possibile procedere in questo modo alla cancellazione, se non cancellando prima le tabelle figlie.

Per procedere comunque ed eliminare _tutte le tabelle_, è possibile specificare di eseguire il DROP anche delle tabelle dipendenti, con l’istruzione CASCADE:

```
DROP TABLE animals CASCADE;

```

# Risorse utili

- [Documentazione ufficiale](https://www.postgresql.org/docs/current/tutorial-inheritance.html)
- [Libro sulle Basi di Dati](https://amzn.to/3ABUix3) (edito da [Apogeo](https://www.apogeonline.com/))