- Le **entità** sono diventate _TABLES_ (tabelle);
- Gli **attributi opzionali** sono diventati _COLUMNS_ (colonne);
- Gli **attributi obbligatori** sono diventati _COLUMNS_ con il vincolo _NOT NULL_;
- Le **chiavi primarie** sono state implementate come _PRIMARY KEYS_ (chiavi primarie);
- Le **chiavi esterne** sono state implementate come _FOREIGN KEYS_ (chiavi esterne);
- Le **chiavi surrogate** sono state implementate come _PRIMARY KEYS_ autoincrementate tramite _SEQUENCES_ (sequenze);
- I **dati derivati** sono stati implementati come _COLUMNS_ aventi dei _TRIGGER_ che le aggiornino.
## Schema dei nomi delle tabelle
Tutte le tabelle sono state istanziate con il nome che le corrispondenti entità avevano nello schema logico, sostituendo tutte le lettere maiuscole con **lettere minuscole**`a-z`, spazi con **underscore**`_` e rimuovendo le parentesi con il loro contenuto.
Inoltre, a tutte le tabelle tranne `utente` è stato dato un nome prefissato da `libro_`, `audiolibro_`, `film_` e `gioco_` per indicare la categoria a cui le entità appartenevano nello schema logico.
Si riportano solo le tabelle con qualche particolarità; le tabelle per la quale la conversione è banale sono omesse da questo file (ma non dal file [`5-database.sql`](5-database.sql)).
La durata delle edizioni degli audiolibri è di tipo _interval_, che rappresenta un intervallo di tempo con la precisione di centesimi di secondo; l'immagine dell'audiolibro ha invece tipo _bytea_, e sarà salvata nel database come un blob binario di dati.
Inoltre, la durata è dotata di un _CHECK_ che impedisce che essa sia minore di 0, convertendo l'_interval_ in secondi e controllando che essi siano maggiori di 0.
Per minimizzare valori nulli, si è tradotta l'associazione binaria 1 a 1 `relativa a` in due tabelle separate, usando in una delle due una chiave esterna come chiave primaria.
Si notino dunque i due _CONSTRAINT_`audiolibro_recensione_pkey` e `id`.
La valutazione delle recensioni deve essere obbligatoriamente tra 0 e 100: a tale scopo, è stato introdotto un _CHECK_ sulla tabella che verifichi questa condizione.
Si può notare nella tabella compare il tipo _char(34)_: essendo gli EIDR sempre lunghi 34 caratteri, si è scelto si minimizzare lo spazio di archiviazione utilizzato rendendo il campo a lunghezza non variabile.
Gli stati e le provenienze dei vari elementi sono state realizzate creando _ENUM_ contenenti tutte le possibili opzioni selezionabili dall'utente, e utilizzandoli come tipo delle relative colonne; in questo modo, si impedisce l'immissione di valori non validi nelle colonne.
La colonna `id` ha un valore di _DEFAULT_ particolare: `nextval('public.elemento_id_seq'::regclass)`.
Ciò significa che, se non viene specificato un `id` durante un inserimento, alla riga verrà assegnato automaticamente il valore corrente della _SEQUENCE_`public.elemento_id_seq` descritta in precedenza, aumentandone inoltre il valore di 1.
Nella tabella è presente anche un _TRIGGER_, che incrementa o decrementa il conteggio degli elementi dell'utente a cui essi appartengono quando uno o più elementi vengono inseriti o rimossi.
La tabella delle edizioni di un libro include due _CHECK_: uno che controlla che le pagine, se specificate, siano un numero positivo, e un'altro che controlla che gli ISBN siano in un formato valido.
In particolare, per quest'ultimo, è stata creata una funzione di utilità `is_numeric`, che verifica che tutti i caratteri di una stringa siano numerici: questa funzione viene poi usata per controllare che tutti i caratteri dell'ISBN siano numeri, permettendo però anche una `X` in ultima posizione (l'ultima cifra degli ISBN più vecchi era in base-11 e utilizzava la lettera X come 10).
Le colonne `*_elementi_posseduti` sono i dati derivati che rappresentano quanti elementi di ogni tipo possiede un dato utente: per i nuovi utenti, questo valore sarà 0.
Queste colonne saranno poi incrementate dai trigger presenti nelle quattro tabelle `*_elemento`.