diff --git a/5-3-creazione-tabelle.md b/5-3-creazione-tabelle.md index 2c244f9..b12a5de 100644 --- a/5-3-creazione-tabelle.md +++ b/5-3-creazione-tabelle.md @@ -192,6 +192,31 @@ ALTER TABLE ONLY public.gioco_elemento ALTER TABLE ONLY public.gioco_elemento ADD CONSTRAINT istanza_di FOREIGN KEY (istanza_di) REFERENCES public.gioco_edizione(id); + +CREATE FUNCTION public.update_n_giochi() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + IF (TG_OP = 'DELETE') THEN + UPDATE utente + SET gioco_elementi_posseduti = gioco_elementi_posseduti - 1 + FROM gioco_elemento + WHERE utente.username = old.appartiene_a; + RETURN old; + ELSIF (TG_OP = 'INSERT') THEN + UPDATE utente + SET gioco_elementi_posseduti = gioco_elementi_posseduti + 1 + FROM gioco_elemento + WHERE utente.username = new.appartiene_a; + RETURN new; + END IF; + END; + $$; + +CREATE TRIGGER numero_giochi_trigger + BEFORE INSERT OR DELETE + ON public.gioco_elemento + FOR EACH ROW EXECUTE PROCEDURE public.update_n_giochi(); ``` Le tabelle degli elementi hanno due colonne `stato` e `provenienza` di tipo `*_stato` e `*_provenienza` rispettivamente: sono gli _ENUM_ creati in precedenza, che impediscono che vengano inseriti valori non consentiti nella tabella. @@ -199,11 +224,43 @@ Le tabelle degli elementi hanno due colonne `stato` e `provenienza` di tipo `*_s La colonna `id` invece ha un valore di _DEFAULT_ particolare: `nextval('public.elemento_id_seq'::regclass)`. Significa che, se non viene specificato un `id` durante un _INSERT_, alla riga verrà assegnato automaticamente il valore corrente della _SEQUENCE_, e il valore della sequenza sarà aumentato, garantendo l'**unicità** degli `id` anche attraverso tabelle diverse. - +Inoltre, nella tabella è presente un _TRIGGER_, che incrementa o decrementa il conteggio dei giochi di un utente quando egli rispettivamente crea o elimina nuovi elementi. ### `libro_edizione` - +```sql +create function is_numeric(text character varying) returns boolean + strict + language plpgsql +as +$$ +DECLARE x NUMERIC; +BEGIN + x = $1::NUMERIC; + RETURN TRUE; +EXCEPTION WHEN others THEN + RETURN FALSE; +END; +$$; + +CREATE TABLE public.libro_edizione ( + isbn character(13) NOT NULL, + titolo_edizione character varying NOT NULL, + pagine integer, + copertina bytea, + relativa_a integer NOT NULL, + CONSTRAINT libro_edizione_isbn_check CHECK ((public.is_numeric(("substring"((isbn)::text, 1, 12))::character varying) AND (public.is_numeric(("right"((isbn)::text, 1))::character varying) OR ("right"((isbn)::text, 1) ~~ '%X'::text)))), + CONSTRAINT libro_edizione_pagine_check CHECK ((pagine >= 0)) +); + +ALTER TABLE ONLY public.libro_edizione + ADD CONSTRAINT libro_edizione_pkey PRIMARY KEY (isbn); + +ALTER TABLE ONLY public.libro_edizione + ADD CONSTRAINT relativa_a FOREIGN KEY (relativa_a) REFERENCES public.libro(id); +``` + +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, assicurandosi che tutti i caratteri siano numerici e permettendo anche una `X` sull'ultimo. ### `utente` diff --git a/5-database.sql b/5-database.sql index 3fb9b0f..ae490dd 100644 --- a/5-database.sql +++ b/5-database.sql @@ -145,18 +145,23 @@ ALTER FUNCTION public.is_numeric(text character varying) OWNER TO cookie; CREATE FUNCTION public.update_n_audiolibri() RETURNS trigger LANGUAGE plpgsql - AS $$BEGIN + AS $$ +BEGIN IF (TG_OP = 'DELETE') THEN UPDATE utente - SET new.audiolibro_elementi_posseduti = old.audiolibro_elementi_posseduti - 1 - WHERE utente.id = new.audiolibro_elemento.appartiene_a; + SET audiolibro_elementi_posseduti = audiolibro_elementi_posseduti - 1 + FROM audiolibro_elemento + WHERE utente.username = old.appartiene_a; + RETURN OLD; ELSIF (TG_OP = 'INSERT') THEN UPDATE utente - SET new.audiolibro_elementi_posseduti = old.audiolibro_elementi_posseduti + 1 - WHERE utente.id = new.audiolibro_elemento.appartiene_a; + SET audiolibro_elementi_posseduti = audiolibro_elementi_posseduti + 1 + FROM audiolibro_elemento + WHERE utente.username = new.appartiene_a; + RETURN new; END IF; - RETURN NEW; -END;$$; +END; +$$; ALTER FUNCTION public.update_n_audiolibri() OWNER TO cookie; @@ -167,18 +172,23 @@ ALTER FUNCTION public.update_n_audiolibri() OWNER TO cookie; CREATE FUNCTION public.update_n_film() RETURNS trigger LANGUAGE plpgsql - AS $$BEGIN + AS $$ +BEGIN IF (TG_OP = 'DELETE') THEN UPDATE utente - SET new.film_elementi_posseduti = old.film_elementi_posseduti - 1 - WHERE utente.id = new.film_elemento.appartiene_a; + SET film_elementi_posseduti = film_elementi_posseduti - 1 + FROM film_elemento + WHERE utente.username = old.appartiene_a; + RETURN old; ELSIF (TG_OP = 'INSERT') THEN UPDATE utente - SET new.film_elementi_posseduti = old.film_elementi_posseduti + 1 - WHERE utente.id = new.film_elemento.appartiene_a; + SET film_elementi_posseduti = film_elementi_posseduti + 1 + FROM film_elemento + WHERE utente.username = new.appartiene_a; + RETURN new; END IF; - RETURN NEW; -END;$$; +END; +$$; ALTER FUNCTION public.update_n_film() OWNER TO cookie; @@ -189,18 +199,23 @@ ALTER FUNCTION public.update_n_film() OWNER TO cookie; CREATE FUNCTION public.update_n_giochi() RETURNS trigger LANGUAGE plpgsql - AS $$BEGIN + AS $$ +BEGIN IF (TG_OP = 'DELETE') THEN UPDATE utente - SET new.gioco_elementi_posseduti = old.gioco_elementi_posseduti - 1 - WHERE utente.id = new.gioco_elemento.appartiene_a; + SET gioco_elementi_posseduti = gioco_elementi_posseduti - 1 + FROM gioco_elemento + WHERE utente.username = old.appartiene_a; + RETURN old; ELSIF (TG_OP = 'INSERT') THEN UPDATE utente - SET new.gioco_elementi_posseduti = old.gioco_elementi_posseduti + 1 - WHERE utente.id = new.gioco_elemento.appartiene_a; + SET gioco_elementi_posseduti = gioco_elementi_posseduti + 1 + FROM gioco_elemento + WHERE utente.username = new.appartiene_a; + RETURN new; END IF; - RETURN NEW; -END;$$; +END; +$$; ALTER FUNCTION public.update_n_giochi() OWNER TO cookie; @@ -211,18 +226,23 @@ ALTER FUNCTION public.update_n_giochi() OWNER TO cookie; CREATE FUNCTION public.update_n_libri() RETURNS trigger LANGUAGE plpgsql - AS $$BEGIN + AS $$ +BEGIN IF (TG_OP = 'DELETE') THEN UPDATE utente - SET new.libro_elementi_posseduti = old.libro_elementi_posseduti - 1 - WHERE utente.id = new.libro_elemento.appartiene_a; + SET libro_elementi_posseduti = libro_elementi_posseduti - 1 + FROM libro_elemento + WHERE utente.username = old.appartiene_a; + RETURN old; ELSIF (TG_OP = 'INSERT') THEN UPDATE utente - SET new.libro_elementi_posseduti = old.libro_elementi_posseduti + 1 - WHERE utente.username = new.libro_elemento.appartiene_a; + SET libro_elementi_posseduti = libro_elementi_posseduti + 1 + FROM libro_elemento + WHERE utente.username = new.appartiene_a; + RETURN new; END IF; - RETURN NEW; -END;$$; +END; +$$; ALTER FUNCTION public.update_n_libri() OWNER TO cookie; @@ -1242,8 +1262,8 @@ COPY public.libro_scritto_da (id_libro, id_autore) FROM stdin; -- COPY public.utente (username, password, email, is_admin, is_banned, libro_elementi_posseduti, audiolibro_elementi_posseduti, film_elementi_posseduti, gioco_elementi_posseduti) FROM stdin; -sas \\x737573 ciao@steffo.eu t f 0 0 0 0 -sis \\x737573 banana@steffo.eu f f 0 0 0 0 +sas \\x737573 ciao@steffo.eu t f -4 0 0 0 +sis \\x737573 banana@steffo.eu f f -2 0 0 0 \. @@ -1324,14 +1344,6 @@ SELECT pg_catalog.setval('public.libro_genere_id_seq', 1, false); SELECT pg_catalog.setval('public.libro_id_seq', 1, false); --- --- Name: libro_edizione Edizione(libro)_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie --- - -ALTER TABLE ONLY public.libro_edizione - ADD CONSTRAINT "Edizione(libro)_pkey" PRIMARY KEY (isbn); - - -- -- Name: audiolibro_edizione audiolibro_edizione_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie -- @@ -1372,14 +1384,6 @@ ALTER TABLE ONLY public.audiolibro_recensione ADD CONSTRAINT audiolibro_recensione_pkey PRIMARY KEY (id); --- --- Name: libro_correlazioni correlazioni_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie --- - -ALTER TABLE ONLY public.libro_correlazioni - ADD CONSTRAINT correlazioni_pkey PRIMARY KEY (id_1, id_2); - - -- -- Name: film_appartenenza_a_genere film_appartenenza_a_genere_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie -- @@ -1572,6 +1576,14 @@ ALTER TABLE ONLY public.libro_autore ADD CONSTRAINT libro_autore_pkey PRIMARY KEY (id); +-- +-- Name: libro_correlazioni libro_correlazioni_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie +-- + +ALTER TABLE ONLY public.libro_correlazioni + ADD CONSTRAINT libro_correlazioni_pkey PRIMARY KEY (id_1, id_2); + + -- -- Name: libro_editore libro_editore_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie -- @@ -1580,6 +1592,14 @@ ALTER TABLE ONLY public.libro_editore ADD CONSTRAINT libro_editore_pkey PRIMARY KEY (parte_isbn); +-- +-- Name: libro_edizione libro_edizione_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie +-- + +ALTER TABLE ONLY public.libro_edizione + ADD CONSTRAINT libro_edizione_pkey PRIMARY KEY (isbn); + + -- -- Name: libro_elemento libro_elemento_pkey; Type: CONSTRAINT; Schema: public; Owner: cookie -- @@ -1636,11 +1656,32 @@ ALTER TABLE ONLY public.utente ADD CONSTRAINT username PRIMARY KEY (username); +-- +-- Name: audiolibro_elemento numero_audiolibri_trigger; Type: TRIGGER; Schema: public; Owner: cookie +-- + +CREATE TRIGGER numero_audiolibri_trigger BEFORE INSERT OR DELETE ON public.audiolibro_elemento FOR EACH ROW EXECUTE PROCEDURE public.update_n_audiolibri(); + + +-- +-- Name: film_elemento numero_film_trigger; Type: TRIGGER; Schema: public; Owner: cookie +-- + +CREATE TRIGGER numero_film_trigger BEFORE INSERT OR DELETE ON public.film_elemento FOR EACH ROW EXECUTE PROCEDURE public.update_n_film(); + + +-- +-- Name: gioco_elemento numero_giochi_trigger; Type: TRIGGER; Schema: public; Owner: cookie +-- + +CREATE TRIGGER numero_giochi_trigger BEFORE INSERT OR DELETE ON public.gioco_elemento FOR EACH ROW EXECUTE PROCEDURE public.update_n_giochi(); + + -- -- Name: libro_elemento numero_libri_trigger; Type: TRIGGER; Schema: public; Owner: cookie -- -CREATE TRIGGER numero_libri_trigger AFTER INSERT ON public.libro_elemento FOR EACH ROW EXECUTE PROCEDURE public.update_n_libri(); +CREATE TRIGGER numero_libri_trigger BEFORE INSERT OR DELETE ON public.libro_elemento FOR EACH ROW EXECUTE PROCEDURE public.update_n_libri(); -- diff --git a/6-operazioni.md b/6-operazioni.md new file mode 100644 index 0000000..b4d8950 --- /dev/null +++ b/6-operazioni.md @@ -0,0 +1,83 @@ +# Query preprogrammate per l'utilizzo del database + +Si sono inserite in questo capitolo della relazione alcuni esempi di query che permetteranno al sito web di interagire con la base di dati. + +Come nel caso della [creazione tabelle](5-3-creazione-tabelle.md), si elencano solo le query più significative. + +## Creazione di un nuovo utente + +```sql +INSERT INTO utente (username, password, email) VALUES ($username, $hashed_password, $email); +``` + +## Promozione di un utente ad amministratore + +```sql +UPDATE utente SET is_admin = true WHERE username = $username; +``` + +## Creazione di un elemento relativo a un libro non esistente nel database + +```sql +INSERT INTO libro (titolo_primario) VALUES ($titolo); + +INSERT INTO libro_edizione (isbn, titolo_edizione, relativa_a) VALUES ($isbn, $titolo, currval('libro_id_seq')); + +INSERT INTO libro_elemento (istanza_di, appartiene_a) VALUES ($isbn, $username); +``` + +## Creazione di una recensione relativa a un elemento + +```sql +INSERT INTO libro_recensione (id, commento, data, valutazione) VALUES ($isbn, $commento, now(), $valutazione); +``` + +## Conteggio degli elementi posseduti da un utente + +```sql +SELECT + libro_elementi_posseduti libri, + audiolibro_elementi_posseduti audiolibri, + film_elementi_posseduti film, + gioco_elementi_posseduti giochi, + (libro_elementi_posseduti + audiolibro_elementi_posseduti + film_elementi_posseduti + gioco_elementi_posseduti) totale +FROM utente +WHERE username = $username; +``` + +## Conteggio del numero totale di edizioni di libri presenti nel database + +```sql +SELECT COUNT(*) FROM libro_edizione; +``` + +## Conteggio del numero totale di edizioni di libri di ogni autore + +```sql +SELECT COUNT(*) +FROM libro_edizione +WHERE relativa_a IN ( + SELECT l.id + FROM libro l + JOIN libro_scritto_da lsd on l.id = lsd.id_libro + JOIN libro_autore la on lsd.id_autore = la.id + WHERE la.id = $id_autore +); +``` + +## Visualizzazione della valutazione media di un gioco + +```sql +SELECT AVG(gr.valutazione) +FROM gioco_recensione gr +JOIN gioco_elemento gel on gr.id = gel.id +JOIN gioco_edizione ge on gel.istanza_di = ge.id +JOIN gioco g on ge.relativa_a = g.id +WHERE g = $id_gioco; +``` + +## Visualizzazione di tutte le edizioni di un dato editore + +```sql +SELECT * FROM libro_editore ld JOIN libro_edizione lz ON ld.parte_isbn = substr(lz.isbn, 5, 5 + length(ld.parte_isbn)); +``` diff --git a/README.md b/README.md index 1f18e45..8f9c77e 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,9 @@ Le specifiche di questo progetto sono disponibili nel file [`spec.pdf`](0-spec.p 4. [Dati derivati](4-4-dati-derivati.md) 5. [Schema logico](4-5-schema-logico.md) 6. [Verifica di normalizzazione](4-6-normalizzazione.md) -5. **Progettazione fisica** +5. **Progettazione fisica** ([dump](5-database.sql)) 1. [Tecnologia database](5-1-tecnologia-database.md) 2. [Creazione database](5-2-creazione-database.md) 3. [Creazione tabelle](5-3-creazione-tabelle.md) 6. **Programmazione database** - + 1. [Query preprogrammate per l'utilizzo del database](6-operazioni.md)