Salta al contenuto
Note per Studenti SQL - definizione dei dati e vincoli

SQL - definizione dei dati e vincoli

In questa pagina 8

Prerequisiti: Modello relazionale - relazioni, chiavi e vincoliIl modello relazionale (Codd, IBM, 1970) rappresenta i dati con relazioni, cioè tabelle, ed è basato su valori: i legami tra relazioni sono confronti di valori, non puntatori, il che garantisce indipendenza dalle strutture fisiche, portabilità e bidirezionalità. Una relazione matematica è un sottoinsieme del prodotto cartesiano di n domini (insieme di n-uple ordinate, senza duplicati né ordine tra le righe); una relazione del modello è un insieme di tuple, funzioni dagli attributi ai valori del dominio, quindi non posizionale. Si distinguono schema di relazione e istanza, schema di base di dati (relazioni più vincoli) e istanza. NULL è un valore speciale fuori da ogni dominio. I vincoli di integrità sono intra-relazionali (di dominio, di tupla, di chiave) e inter-relazionali (integrità referenziale, con la chiave esterna). Superchiave: insieme di attributi che non ripete mai i valori; chiave: superchiave minimale; ogni relazione ne ha almeno una (tutti gli attributi); la chiave primaria è una chiave scelta, senza NULL.Modello relazionale - relazioni, chiavi e vincoli → (chiavi, chiavi esterne, vincoli di integrità) e la traduzione dallo schema ER in Ristrutturazione dello schema ER e traduzione nel modello relazionaleLa progettazione logica ha due passi. 1) Ristrutturazione dello schema ER, per togliere i costrutti che il modello relazionale non esprime: analisi delle ridondanze (attributi derivati e cicli di relazioni, decisa con volume dei dati e carico, tabelle di frequenza e accessi), eliminazione degli attributi multivalore (nuova entità), composti (appiattiti o nuova entità), delle IS-A (relazione con partecipazione (1,1) dalla sottoclasse) e delle generalizzazioni (opzione 1 relazioni, 2 accorpamento nel padre con attributo discriminante, 3 accorpamento nei figli, solo se completa e disgiunta), scelta degli identificatori principali (niente cicli di identificazione esterna), riscrittura dei vincoli esterni, partizionamento e accorpamento di entità. 2) Traduzione quasi automatica nel modello relazionale: ogni entità diventa una relazione con la chiave primaria data dall'identificatore principale (anche esterno); una relazione molti-a-molti diventa una relazione con le chiavi delle entità; una uno-a-molti con partecipazione obbligatoria si fonde con l'entità dal lato max 1 con una chiave esterna; con partecipazione opzionale si fonde (NULL) o si crea una relazione a parte; le uno-a-uno si fondono sul lato con partecipazione obbligatoria; le ternarie seguono la stessa logica con le chiavi di tutte le entità.Ristrutturazione dello schema ER e traduzione nel modello relazionale →: qui si trasforma lo schema relazionale in istruzioni SQL. Le interrogazioni sono in SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni →. Un esempio completo, con DDL, DML e interrogazioni, è nell'esercizio Esercizio - Laboratorio sul social network - DDL, DML e interrogazioni (laboratorio).

I comandi seguenti sono quelli di PostgreSQL, il DBMS del corso. Dove SQLite (che si è usato per provare gli esempi) si comporta in modo diverso, lo si dice.

Il linguaggio SQL

SQL è un linguaggio dichiarativo: si dice che cosa si vuole, non come ottenerlo (è il DBMS a scegliere il piano, vedi Organizzazione fisica dei dati e accesso programmatico alle basi di datiUn DBMS è formato da un gestore delle connessioni, un parser, un ottimizzatore che sceglie il piano di esecuzione usando le statistiche del catalogo, un esecutore, i metodi di accesso (heap, ordinato, hash, B-tree, indici), il buffer manager e il gestore delle transazioni (lock e log). Il costo si misura in accessi a blocchi del disco. L'ottimizzatore riscrive l'espressione algebrica (selezioni e proiezioni il prima possibile, prodotto con selezione = join, ordine dei join) e sceglie gli algoritmi: scansione o indice per le selezioni, nested loop, block nested loop, index nested loop, sort-merge o hash join per i join (con 1000 e 100 blocchi, 10 pagine di buffer: 11 mila accessi con block nested loop, 3300 con hash join). La progettazione fisica sceglie organizzazione dei file, indici ed eventuale denormalizzazione in base al carico. Le applicazioni accedono ai dati con SQL incorporato, interfacce a livello di chiamata (ODBC, JDBC, DB-API di Python), ORM o routine memorizzate: connessione, cursore, execute con parametri, fetch, commit o rollback. Mai concatenare l'input dell'utente nell'SQL (SQL injection): query parametrizzate. Un'applicazione web è a tre livelli: browser, server applicativo (HTTP senza stato, sessioni e cookie) e DBMS.Organizzazione fisica dei dati e accesso programmatico alle basi di dati →). Si compone di:

  • DDL (Data Definition Language): crea e modifica la struttura (database, schemi, tabelle, vincoli, viste, indici);
  • DML (Data Manipulation Language): legge e modifica i dati (SELECT, INSERT, UPDATE, DELETE).

Implementa il modello relazionale e l'algebra (Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →) con alcune estensioni. Lo standard è ISO/IEC 9075 (SQL-86, SQL-89, SQL-92, SQL:1999 e seguenti, fino a SQL:2016); ha tre livelli di conformità: Entry, Intermediate (quello implementato da quasi tutti i DBMS commerciali) e Full. Vantaggi: curva di apprendimento bassa, portabilità e longevità delle applicazioni. Svantaggi: ogni DBMS ha le sue varianti (portabilità limitata), il linguaggio è lontano da uno "ideale", e lo standard lascia alcune scelte implementation-defined o implementation-dependent.

Tabelle, righe, query

  • Tabella di base (base table): contiene i dati; è un insieme di zero o più colonne e zero o più righe; le righe non sono ordinate e hanno tutte lo stesso tipo di riga; due colonne non possono avere lo stesso nome.
  • Interrogazione: operazione su una o più tabelle che restituisce una tabella derivata. Le righe di una tabella derivata possono essere ordinate (ORDER BY) e la tabella può avere più colonne con lo stesso nome.
  • Una tabella SQL è un multi-insieme di righe: può contenere duplicati. Quindi non è una relazione in senso stretto (nell'algebra una relazione è un insieme).

Catalogo, schema e identificatori

Un catalogo è un insieme di schemi; uno schema è un insieme di descrittori di oggetti (tabelle, viste, domini...). Come si creano è implementation-defined. Lo information schema descrive tutti gli oggetti del catalogo.

Parole chiave e identificatori sono insensibili alle maiuscole. Un identificatore regolare è di al più 128 caratteri, inizia con una lettera, contiene lettere, cifre e _, e non può essere una parola riservata. Un identificatore delimitato è tra doppi apici ("SELECT" è valido come nome) ed è sensibile alle maiuscole: "SELECT", "select" e "SeLeCt" sono tre identificatori diversi.

Database e schema

sql
CREATE DATABASE Example ENCODING 'UTF-8';   -- PostgreSQL
DROP DATABASE Example;

CREATE SCHEMA Test;
DROP SCHEMA Test CASCADE;
  • DROP SCHEMA ... CASCADE cancella anche tutti gli oggetti dello schema; RESTRICT (il comportamento predefinito) cancella lo schema solo se è vuoto. Lo stesso CASCADE/RESTRICT vale per DROP TYPE, DROP DOMAIN, DROP TABLE, DROP VIEW, DROP INDEX, DROP TRIGGER.
  • Nello stesso catalogo si possono creare più schemi, di proprietari diversi; di norma gli oggetti creati in uno schema appartengono al suo proprietario.

Tipi di dato

Tipo Significato
CHAR(n), CHARACTER(n) stringa a lunghezza fissa di esattamente nn caratteri
VARCHAR(n), CHARACTER VARYING(n) stringa a lunghezza variabile fino a nn caratteri
BINARY(n), VARBINARY(n) stringa di byte (in PostgreSQL BYTEA)
NUMERIC(p, s) numero esatto con pp cifre totali e ss decimali: per importi di denaro e dove serve esattezza
SMALLINT, INTEGER, BIGINT interi con segno (in PostgreSQL 2, 4, 8 byte)
REAL, DOUBLE PRECISION virgola mobile (4 byte con 6 cifre, 8 byte con 15 cifre)
SMALLSERIAL, SERIAL, BIGSERIAL intero autoincrementale (solo PostgreSQL)
BOOLEAN valori logici
DATE, TIME, TIMESTAMP data, ora, data e ora, con o senza fuso (WITH/WITHOUT TIME ZONE)
INTERVAL intervallo di tempo

Tipi avanzati di PostgreSQL:

  • UUID: identificatore a 128 bit, per esempio a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11, generato in modo che sia praticamente impossibile ottenere lo stesso valore due volte (il modulo uuid-ossp fornisce le funzioni di generazione);
  • tipi intervallo (int4range, int8range, numrange, tsrange, tstzrange, daterange): rappresentano molti valori in uno solo (per esempio le ore in cui una sala riunioni è prenotata) ed esprimono bene la sovrapposizione tra intervalli; il sottotipo deve avere un ordine totale;
  • json e jsonb: json conserva il testo esatto e lo rianalizza a ogni uso, jsonb è in formato binario, più lento da scrivere ma molto più veloce da interrogare, e supporta gli indici. Sono la strada flessibile verso i database NoSQL.

Tipo enumerato (insieme statico e ordinato di valori; l'ordine è quello della creazione):

sql
CREATE TYPE visibility AS ENUM ('public', 'private', 'friends');
DROP TYPE visibility CASCADE;     -- o RESTRICT (predefinito)

Dominio definito dall'utente: un tipo con un vincolo, riusabile in più tabelle.

sql
CREATE DOMAIN Identifier AS VARCHAR(32);

CREATE DOMAIN Mark AS SMALLINT
  DEFAULT NULL
  CHECK (VALUE >= 18 AND VALUE <= 30);

DEFAULT dà il valore usato se non se ne specifica uno; NOT NULL/NULL indica se NULL è ammesso; CHECK pone vincoli aggiuntivi su VALUE. DROP DOMAIN Identifier CASCADE cancella anche gli oggetti che dipendono dal dominio.

In SQLite non esistono CREATE DOMAIN, CREATE TYPE ... ENUM, SERIAL, UUID, tipi intervallo né jsonb: si usano VARCHAR/TEXT, CHECK (x IN (...)) per gli enumerati, INTEGER PRIMARY KEY AUTOINCREMENT per gli autoincrementali. I tipi sono "indicazioni": SQLite non li impone rigidamente.

Creare una tabella

La definizione di una tabella è l'elenco delle colonne con nome, tipo e vincoli, seguito dagli eventuali vincoli sulla tabella intera.

I vincoli

Vincolo Significato
NOT NULL il valore NULL non è ammesso. È implicito nella chiave primaria
DEFAULT <costante> valore assegnato all'inserimento se non specificato; può essere una costante, NULL o una funzione senza argomenti (CURRENT_USER, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP)
CHECK (<espressione>) vincolo di dominio se riferito a una sola colonna, vincolo di tupla se a livello di tabella (confronta più colonne della stessa riga)
PRIMARY KEY (c1, c2,...) chiave primaria, composta da una o più colonne. Una sola per tabella; si può dare un nome al vincolo
UNIQUE (c1, c2,...) una chiave non primaria (una colonna o più): non ammette righe ripetute
FOREIGN KEY (c1,...) REFERENCES T(d1,...) chiave esterna con vincolo di integrità referenziale: i valori di c1,... devono comparire come valori di d1,... in T (o essere NULL)

Per la chiave esterna si dichiara anche che cosa fare quando la riga puntata viene cancellata o modificata:

sql
FOREIGN KEY (...) REFERENCES T(...)
    [ON DELETE {NO ACTION | CASCADE | SET NULL | SET DEFAULT}]
    [ON UPDATE {NO ACTION | CASCADE | SET NULL | SET DEFAULT}]
  • NO ACTION (predefinito): l'operazione è vietata;
  • CASCADE: si cancellano (o si aggiornano) anche tutte le righe che puntano;
  • SET NULL: le colonne della chiave esterna diventano NULL;
  • SET DEFAULT: le colonne diventano il valore di default dichiarato.

È la versione in SQL delle scelte restrict/cascade/set null/set default viste in Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →.

Un esempio completo: i riferimenti bibliografici

Schema relazionale (la chiave primaria è id, tranne in Information, dove è reference, e in Write): Author(id, name, surname), Publisher(id, name), Reference(id, title, year, publisher) con publisher →\to Publisher, Information(reference, notes) con reference →\to Reference, Write(reference, author, authorNumber) con chiave (reference,author)(\text{reference},\text{author}) e le due chiavi esterne.

sql
CREATE DOMAIN Identifier AS VARCHAR(32);

CREATE TABLE Author (
  id      Identifier PRIMARY KEY,           -- vincolo di colonna
  name    VARCHAR(30),
  surname VARCHAR(30) NOT NULL
);

CREATE TABLE Publisher (
  id   Identifier,
  name VARCHAR(150) NOT NULL,
  PRIMARY KEY (id)                          -- vincolo di tabella: equivalente
);

CREATE TABLE Reference (
  id        Identifier,
  title     VARCHAR(200) NOT NULL,
  year      SMALLINT NOT NULL CHECK (year > 0),
  publisher Identifier,
  PRIMARY KEY (id),
  FOREIGN KEY (publisher) REFERENCES Publisher(id)
);

CREATE TABLE Information (
  reference Identifier,
  notes     VARCHAR(200) NOT NULL,
  PRIMARY KEY (reference),
  FOREIGN KEY (reference) REFERENCES Reference(id)
);

CREATE TABLE Write (
  reference    Identifier,
  author       Identifier,
  authorNumber SMALLINT DEFAULT 1 NOT NULL CHECK (authorNumber > 0),
  PRIMARY KEY (reference, author),          -- chiave primaria COMPOSTA
  FOREIGN KEY (reference) REFERENCES Reference(id),
  FOREIGN KEY (author)    REFERENCES Author(id)
);

Punti da notare:

  • Ordine di creazione: Publisher prima di Reference, perché una chiave esterna può puntare solo a una tabella già esistente (o a una tabella aggiunta dopo con ALTER TABLE). Per cancellare si fa l'inverso, oppure DROP TABLE ... CASCADE.
  • Information ha come chiave primaria la stessa chiave esterna: è la traduzione di una relazione 1-a-1 (almeno 0 o 1 informazione per riferimento).
  • Write è la traduzione di una relazione molti-a-molti: la chiave è la coppia. Scrivere PRIMARY KEY accanto a ciascuna delle due colonne non significa chiave composta ma tentare di creare due chiavi primarie, e dà errore (SQLite: table has more than one primary key).
  • authorNumber è la posizione dell'autore nell'elenco: DEFAULT 1, NOT NULL e CHECK (authorNumber > 0) insieme.

Chiavi e NULL. UNIQUE ammette più righe con NULL (due NULL non sono "uguali"), mentre la chiave primaria non ammette NULL. Con email VARCHAR(50) UNIQUE, due righe con email = NULL sono accettate, due con 'a@x' no (verificato).

Esempio di vincoli violati

Con PRAGMA foreign_keys = ON in SQLite (in PostgreSQL le chiavi esterne sono sempre attive) sulle tabelle sopra:

Istruzione Esito
INSERT INTO Write VALUES ('T1996','TanenbaumAS',1) due volte errore: la chiave (reference,author)(\text{reference},\text{author}) esiste già
INSERT INTO Write VALUES ('T2001','Nessuno',1) errore: l'autore Nessuno non esiste (chiave esterna)
INSERT INTO Write VALUES ('T2001','TanenbaumAS',0) errore: CHECK (authorNumber > 0)
INSERT INTO Reference VALUES ('X','Senza titolo',-5,'PH') errore: CHECK (year > 0)
INSERT INTO Reference(id, year) VALUES ('Y', 2000) errore: title è NOT NULL e non ha default
INSERT INTO Reference VALUES ('Z','Ok',2000,NULL) accettato: publisher può essere NULL

Modificare ed eliminare una tabella

sql
ALTER TABLE Author ADD COLUMN SecondName VARCHAR(20);

ALTER TABLE Author
  DROP COLUMN Surname,
  ADD COLUMN Surname VARCHAR(50);

ALTER TABLE Author DROP CONSTRAINT author_pkey,         -- PostgreSQL: si toglie per nome
                   ADD PRIMARY KEY (name);

DROP TABLE Author CASCADE;       -- cancella anche le tabelle che la referenziano via FK

ALTER TABLE aggiunge o toglie colonne e vincoli. Cancellare una colonna perde i suoi dati. La forma DROP PRIMARY KEY è di MySQL: in PostgreSQL si cancella il vincolo per nome (DROP CONSTRAINT). DROP TABLE ... RESTRICT (predefinito) rifiuta se un altro oggetto dipende dalla tabella.

Manipolazione dei dati

Inserimento. Si può omettere l'elenco delle colonne se si danno tutti i valori nell'ordine della tabella; con l'elenco si omettono le colonne con default (o NULL):

sql
INSERT INTO Author VALUES ('BuckJR', 'John R.', 'Buck');
INSERT INTO Write VALUES ('Tanenbaum2001', 'TanenbaumAS', DEFAULT);   -- PostgreSQL
INSERT INTO Write (reference, author) VALUES ('Tanenbaum2001', 'TanenbaumAS');   -- equivalente, valido anche in SQLite

La parola DEFAULT dentro VALUES è di PostgreSQL; SQLite non la accetta (si omette la colonna).

Cancellazione. Senza WHERE si cancellano tutte le righe (la tabella resta):

sql
DELETE FROM Write;                          -- svuota la tabella
DELETE FROM Write WHERE author = 'BuckJR';  -- solo le righe di quell'autore

Modifica.

sql
UPDATE Author SET name = 'Giacomo' WHERE surname = 'Pagano';
UPDATE Author SET name = 'Giacomo';                              -- TUTTE le righe!
UPDATE Write  SET authorNumber = authorNumber + 1;               -- espressione sul valore vecchio
UPDATE Write  SET authorNumber = authorNumber + 1
  WHERE reference = 'CastelliPagano2002a';

Nel SET il valore a destra è calcolato sulla riga prima della modifica. Un UPDATE o DELETE senza WHERE agisce su tutta la tabella: è l'errore più costoso (si può proteggere con una transazione, vedi SQL avanzato - indici, transazioni e triggerUn file di record può essere heap (inserimento in ordine, ricerca per uguaglianza in media n/2 accessi), ordinato (log2 n), hash (costante, solo uguaglianza) o B-tree (log_F n, anche intervalli). Un indice è una struttura ausiliaria di coppie (chiave K, puntatore P) ordinate, molto più piccola della tabella: l'indice primario è sul campo di ordinamento del file ordinato (una chiave per blocco, non denso, log2(m)+1 accessi), l'indice secondario è su un campo qualsiasi (denso). CREATE [UNIQUE] INDEX, anche su espressioni; PostgreSQL usa tabelle heap con indici secondari B-tree (predefinito) o hash, e PRIMARY KEY e UNIQUE creano un indice implicito. Gli indici velocizzano le letture ma costano nelle scritture e in spazio. Una transazione è una sequenza atomica di operazioni con proprietà ACID (atomicità, consistenza, isolamento, durabilità): START TRANSACTION, COMMIT, SAVEPOINT, ROLLBACK [TO SAVEPOINT]. Un trigger è una regola evento-condizione-azione (ECA): BEFORE/AFTER, ROW/STATEMENT, WHEN, con funzione PL/pgSQL che usa NEW e OLD; serve per vincoli complessi e attributi derivati.SQL avanzato - indici, transazioni e trigger →).

Effetto delle azioni sulle chiavi esterne (provato)

Con Reference.publisher REFERENCES Publisher(id) ON DELETE SET NULL ON UPDATE CASCADE e Write.reference REFERENCES Reference(id) ON DELETE CASCADE:

  • UPDATE Publisher SET id = 'PRH' WHERE id = 'PH': tutte le righe di Reference con publisher = 'PH' diventano 'PRH' (cascade);
  • DELETE FROM Publisher WHERE id = 'PRH': quelle righe restano, con publisher = NULL (set null);
  • DELETE FROM Reference WHERE id = 'T1996': spariscono anche le righe di Write con quel riferimento (cascade);
  • una chiave esterna senza azione (NO ACTION): DELETE FROM Author WHERE id = 'TanenbaumAS' fallisce finché esistono righe di Write che puntano all'autore.
  • con ON DELETE SET DEFAULT la colonna torna al suo default (che deve esistere come valore della tabella referenziata).

Quale azione scegliere? CASCADE per le entità dipendenti (le righe di Write non hanno senso senza il riferimento), SET NULL per legami opzionali (un riferimento può non avere un editore), NO ACTION per le entità importanti (non si deve poter cancellare un autore per sbaglio).

Errori tipici

Domande d'esame

1. Scrivere in SQL la tabella Write(reference, author, authorNumber) con chiave primaria sui primi due attributi, chiavi esterne verso Reference e Author, e authorNumber positivo con valore di default 1. Traccia. Come nell'esempio: PRIMARY KEY (reference, author) a livello di tabella, due FOREIGN KEY, authorNumber SMALLINT DEFAULT 1 NOT NULL CHECK (authorNumber > 0).

2. Cosa succede con ON DELETE CASCADE, SET NULL e NO ACTION se si cancella la riga referenziata? Traccia. CASCADE cancella le righe che puntano; SET NULL mette a NULL la chiave esterna (non è possibile se fa parte della chiave primaria); NO ACTION (predefinito) vieta l'operazione.

3. Differenza tra tabella SQL e relazione. Traccia. La relazione è un insieme di tuple, senza duplicati e senza ordine; la tabella SQL è un multi-insieme: ammette righe uguali, a meno che una chiave o DISTINCT non le eviti.

Versione ripasso

Linguaggio: SQL è dichiarativo. DDL crea e modifica la struttura; DML legge e modifica i dati (SELECT, INSERT, UPDATE, DELETE). Standard ISO 9075, livelli Entry, Intermediate, Full. Una tabella SQL è un multi-insieme di righe (ammette duplicati): non è una relazione in senso stretto. Le righe non sono ordinate. Identificatori regolari insensibili alle maiuscole; quelli delimitati "..." sono sensibili. Base: Modello relazionale - relazioni, chiavi e vincoliIl modello relazionale (Codd, IBM, 1970) rappresenta i dati con relazioni, cioè tabelle, ed è basato su valori: i legami tra relazioni sono confronti di valori, non puntatori, il che garantisce indipendenza dalle strutture fisiche, portabilità e bidirezionalità. Una relazione matematica è un sottoinsieme del prodotto cartesiano di n domini (insieme di n-uple ordinate, senza duplicati né ordine tra le righe); una relazione del modello è un insieme di tuple, funzioni dagli attributi ai valori del dominio, quindi non posizionale. Si distinguono schema di relazione e istanza, schema di base di dati (relazioni più vincoli) e istanza. NULL è un valore speciale fuori da ogni dominio. I vincoli di integrità sono intra-relazionali (di dominio, di tupla, di chiave) e inter-relazionali (integrità referenziale, con la chiave esterna). Superchiave: insieme di attributi che non ripete mai i valori; chiave: superchiave minimale; ogni relazione ne ha almeno una (tutti gli attributi); la chiave primaria è una chiave scelta, senza NULL.Modello relazionale - relazioni, chiavi e vincoli → e Ristrutturazione dello schema ER e traduzione nel modello relazionaleLa progettazione logica ha due passi. 1) Ristrutturazione dello schema ER, per togliere i costrutti che il modello relazionale non esprime: analisi delle ridondanze (attributi derivati e cicli di relazioni, decisa con volume dei dati e carico, tabelle di frequenza e accessi), eliminazione degli attributi multivalore (nuova entità), composti (appiattiti o nuova entità), delle IS-A (relazione con partecipazione (1,1) dalla sottoclasse) e delle generalizzazioni (opzione 1 relazioni, 2 accorpamento nel padre con attributo discriminante, 3 accorpamento nei figli, solo se completa e disgiunta), scelta degli identificatori principali (niente cicli di identificazione esterna), riscrittura dei vincoli esterni, partizionamento e accorpamento di entità. 2) Traduzione quasi automatica nel modello relazionale: ogni entità diventa una relazione con la chiave primaria data dall'identificatore principale (anche esterno); una relazione molti-a-molti diventa una relazione con le chiavi delle entità; una uno-a-molti con partecipazione obbligatoria si fonde con l'entità dal lato max 1 con una chiave esterna; con partecipazione opzionale si fonde (NULL) o si crea una relazione a parte; le uno-a-uno si fondono sul lato con partecipazione obbligatoria; le ternarie seguono la stessa logica con le chiavi di tutte le entità.Ristrutturazione dello schema ER e traduzione nel modello relazionale →.

Database e schema: CREATE/DROP DATABASE, CREATE/DROP SCHEMA. DROP ... CASCADE cancella anche gli oggetti dipendenti; RESTRICT (predefinito) cancella solo se vuoto.

Tipi:

  • CHAR(n) lunghezza fissa, VARCHAR(n) variabile fino a nn;
  • NUMERIC(p,s) per gli importi di denaro: REAL e FLOAT arrotondano;
  • SMALLINT, INTEGER, BIGINT; SERIAL (solo PostgreSQL, autoincrementale);
  • BOOLEAN, DATE, TIME, TIMESTAMP, INTERVAL;
  • PostgreSQL: UUID, tipi intervallo (daterange e simili), json (testo) e jsonb (binario, indicizzabile).
sql
CREATE TYPE visibility AS ENUM ('public', 'private', 'friends');
CREATE DOMAIN Mark AS SMALLINT DEFAULT NULL CHECK (VALUE >= 18 AND VALUE <= 30);

Un dominio è un tipo con un vincolo, riusabile in più tabelle.

CREATE TABLE: elenco di colonne con nome, tipo e vincoli, seguito dai vincoli di tabella.

Vincolo Significato
NOT NULL NULL non ammesso; implicito nella chiave primaria
DEFAULT valore se non specificato: costante, NULL, CURRENT_DATE...
CHECK (...) su una colonna è vincolo di dominio; a livello di tabella è vincolo di tupla
PRIMARY KEY (...) una sola per tabella, anche composta; implica NOT NULL
UNIQUE (...) niente righe ripetute; ammette più NULL
FOREIGN KEY (c) REFERENCES T(d) integrità referenziale: i valori compaiono in T oppure sono NULL

Azioni sulle chiavi esterne: ON DELETE e ON UPDATE con NO ACTION (predefinito, vieta l'operazione), CASCADE, SET NULL, SET DEFAULT. Sono le scelte restrict/cascade/set null/set default di Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →. Scelta: cascade per le entità dipendenti, set null per i legami opzionali, no action per le entità importanti.

Esempio: riferimenti bibliografici. Write(reference, author, authorNumber) traduce una relazione molti-a-molti; Information(reference, notes) è 1-a-1 con chiave uguale alla chiave esterna:

sql
CREATE TABLE Write (
  reference    Identifier,
  author       Identifier,
  authorNumber SMALLINT DEFAULT 1 NOT NULL CHECK (authorNumber > 0),
  PRIMARY KEY (reference, author),
  FOREIGN KEY (reference) REFERENCES Reference(id),
  FOREIGN KEY (author)    REFERENCES Author(id)
);
  • Si crea prima la tabella referenziata (Publisher prima di Reference).
  • PRIMARY KEY scritto accanto a ciascuna colonna crea due chiavi primarie e dà errore: la chiave composta va a livello di tabella.

ALTER e DROP:

sql
ALTER TABLE Author ADD COLUMN SecondName VARCHAR(20);
DROP TABLE Author CASCADE;   -- cancella anche le tabelle che la referenziano

ADD/DROP COLUMN e ADD/DROP CONSTRAINT. Cancellare una colonna perde i suoi dati. In PostgreSQL il vincolo di chiave si toglie per nome (DROP CONSTRAINT), non con DROP PRIMARY KEY (MySQL).

DML:

sql
INSERT INTO Write (reference, author) VALUES ('Tanenbaum2001', 'TanenbaumAS');
DELETE FROM Write WHERE author = 'BuckJR';
UPDATE Write SET authorNumber = authorNumber + 1 WHERE reference = 'CastelliPagano2002a';
  • Senza WHERE, DELETE e UPDATE agiscono su tutta la tabella. È l'errore più costoso.
  • Nel SET il valore a destra si calcola sulla riga prima della modifica.
  • DEFAULT dentro VALUES è di PostgreSQL.

SQLite: niente DOMAIN, ENUM, SERIAL, UUID; per gli enumerati CHECK (x IN (...)), per gli autoincrementali INTEGER PRIMARY KEY AUTOINCREMENT. Le chiavi esterne sono attive solo con PRAGMA foreign_keys = ON.

Errori tipici

  • PRIMARY KEY ripetuto su due colonne invece del vincolo di tabella.
  • Tabelle create o cancellate nell'ordine sbagliato.
  • REAL o FLOAT per i soldi.
  • UPDATE o DELETE senza WHERE.
  • Dimenticare che UNIQUE ammette più NULL.

Domande d'esame (tracce)

  • Write con chiave su due attributi, due chiavi esterne e authorNumber positivo con default 1: vincolo di tabella per la chiave, DEFAULT 1 NOT NULL CHECK (authorNumber > 0) sulla colonna.
  • ON DELETE SET NULL non è possibile se la chiave esterna fa parte della chiave primaria.
  • Tabella SQL e relazione: la relazione è un insieme senza duplicati, la tabella SQL può averne.

Esempio completo: Esercizio - Laboratorio sul social network - DDL, DML e interrogazioni (laboratorio). Seguito: SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni →.

Esercizi su questo argomento

Teoria collegata