Usiamo un’architettura standard a 3 livelli per i DBMS, lo standard ANSI / SPARC:
- Livello interno - implementa le strutture fisiche di memorizzazione (file sequenziali, file hash etc…)
- Livello logico - Fornisce un modello logico dei dati, indipendenti da come sono memorizzati fisicamente, il modello relazione
- Livello esterno - Fornisce una o più descrizioni di porzioni della base di dati indipendenti dallo schema logico infatti può prevedere organizzazioni dei dati alternative rispetto a quelle utilizzate.
Quindi un esempio di livello logico è:
Mentre per il livello esterno:
Questa è una possibile vista del database, ogni utente con diversi privilegi avrà una vista diversa.
Il linguaggio SQL ci fornisce delle strutture per operare:
- A livello logico
- Data Definition Language (DDL) - per creare schemi di relazioni
- Data Manipolation Language (DML) - Per interrogare ed aggiornare i dati
- A livello esterno - costrutti DDL per creare viste della base di dati
Creazione di Database, Schemi e Tabelle
create database nome_database [opzioni]
Crea un database
create schema nome_schema [opzioni]
Crea uno schema (namespace) all'interno del database corrente
create table nome_table (...)
Crea una nuova tabella all'interno di uno schema del database corrente
Creazione di Tabelle
create table [nome_schema]nome_tabella (
nome_attributo dominio [vincoli di dominio]
...
[altri vincoli intra-relazionali]
[vincoli inter-relazionali]
)
Il nome della schema è opzionale e se omesso viene usato lo schema di default senza nome.
Esempio
create table Corso (
codice integer not null,
nome character varying (100) not null,
aula character varying (10) not null,
primary key (codice)
)
create table Incarico (
docente integer not null,
corso integer not null,
primary key (docente, corso),
foreign key (docente) references Docente(matr),
foreign key (corso) references Corso(codice)
)
Domini SQL predefiniti
- Domini numerici
- interi: integer, smallint…
- decimali: numeric(prec, scala), decimali(prec, scala)
- approssimati: float(prec), real, double precision
- Stringhe
- character [varying] (lung_max) (abbrev. in char / varchar)
- text
- …
- Istanti temporali
- date (tipo record con campi per anno, mese, giorno)
- time (tipo record con campi per ora, min, sec)
- timestamp (tipo record con campi per anno, …, sec)
- Intervalli temporali: interval
- Valori booleani: Boolean, da SQL:1999 in poi
- Dati non strutturati di grandi dimensioni: CLOB e BLOB
Valori di Deafult
create table Impiegato (
nome ...,
cognome ...,
stipendio integer default 0,
...
)
Se durante un inserimento o una modifica di questa tabella non viene indicato un valore per la colonna stipendio allora questo verrà impostato a 0.
Vincoli di Dominio
create table Impiegato (
nome varchar(100) not null ,
cognome varchar(100) not null ,
stipendio integer default 0
check ( stipendio >= 0) ,
...
)
- Ogni ennupla deve soddisfare il vincolo
stipendio >= 0
- Il vincolo viene controllato in automatico all’inserimento e alla modifica
- In caso di violazione, l’inserimento o la modifica non avvengono e viene generato un errore.
Vincoli di chiave
create table Studente (
matricola integer not null,
nome varchar(100) not null,
cognome varchar(100) not null,
nascita date,
cf character(16) not null,
// Chiave primaria (implica not null)
primary key (matricola),
unique (cf), //altra chiave
unique (cognome, nome, nascita) //altra chiave
)
Se il vincolo di chiave è su un solo attributo possiamo usare anche:
create table Studente (
matricola integer primary key, // implica not null
...
)
SQL e modello relazionale
Una tabella SQL non rappresenta sempre una relazione infatti può contenere ennuple uguali, affinché rappresenti una relazione è necessario definire almeno una chiave.
Esempio
create table Studente (
matr integer not null,
cognome varchar(100) not null,
nome varchar(100) not null
)
Da questa tabella possiamo ottenere:
Mentre con questa:
create table Studente (
matr integer not null,
cognome varchar(100) not null,
nome varchar(100) not null,
primary key (matr)
)
Non può accadere la situazione di prima con ennuple uguali.
Vincoli di integrità referenziale
Costruiamo un database di esempio
create table Officina (
nome varchar(100) not null,
indirizzo varchar(500) not null,
primary key (nome)
)
create table Veicolo (
targa char(8) not null,
tipo varchar(50) not null,
primary key (targa)
)
create table Riparazione (
officina varchar(100) not null,
codice integer not null,
veicolo char(8) not null
primary key (officina, codice)
foreign key (officina) references Officina(nome),
foreign key (veicolo) references Veicolo(targa)
)
create table RicambioRip (
officina varchar(100) not null,
rip int not null,
ricambio char(5) not null,
primary key (officina, rip, ricambio),
foreign key (officina) references Officina(nome),
foreign key (rip) references Riparazione(codice)
)
Modifica e Cancellazione di tabelle, schemi e database
Modifca:
alter table
alter table add column
alter table drop column
alter table alter column
alter table add constraint
alter table drop constraint
- …
Per la cancellazione.
drop table <nome tabella>
drop schema <nome schema>
drop database <nome database>
Domini SQL definiti dall’utente
Per l’utente è possibile definire:
- Domini specializzazione di altri domini
- Domini di tipo enumerativo
- Domini di tipo record
Ed SQL offre due comandi per fare questo:
create domain
create type
Che offrono diverse funzionalità
Domini speciallizati
Un dominio specializzato definisce un sottoinsieme di valori di un dominio esistente
create domain nome_dominio as tipo_base
[valore di default]
[vincolo]
Esempio - Definizione del dominio voto
create domain voto as integer
default 0
check (value >= 18 and value <= 30)
Domini Enumerativi
Un dominio enumerativo definisce un insieme finito, piccolo e stabile di valori ognuno identificato da un’etichetta.
create type nome_dominio as enum('valore1',..., 'valore N')
Esempio - Definizione del dominio genere
create type genere as enum('M', 'F')
Etichette delle enum
Le etichette delle enum non sono strighe ma identificatori veri e propri.
Domini Tipi Record
I valori di un dominio di tipo record (o dominio composto) sono record di valori, uno per ogni campo del dominio. Il valore di ogni campo di un record è del rispettivo dominio.
create type nome_dominio as (
campo1 dominio1, ..., campoN dominioN
)
Esempio - Definizione del dominio composto indirizzo
create type indirizzo (
via varchar(200), citta varchar(100)
)
Costrutto Create type
Il costrutto create type non è implementato di standard e a seconda della versione può soffrire alcune limitazioni.
Modifica e Cancellazione di Domini
Tutti i domini che abbiamo creato possono essere modificati o rimossi.
Modifica:
alter domain <nome dominio>
alter type <nome dominio>
Cancellazione:
drop dominio <nome dominio>
drop type <nome dominio>
Generazione di Valori Progressivi
In alcune situazioni è necessario aggiungere un identificatore artificiale in una entità e quindi un attributo aggiuntivo.
Esempio
In questi casi è possibile lasciare al DBMS il compito di assegnare valori diversi per il campo id (generalmente progressivi) alle diverse ennuple.
Con PostgreSQL usiamo il seguente costrutto:
create table Prenotazione (
id integer default nextval ('Prenotazione_id_seq') not null,
istante timestamp not null,
primary key (id)
);
Oppure in modo più breve:
create table Prenotazione (id serial not null, ...)
Per inserire ennuple:
insert into Prenotazione(istante)
values ('2011-08-24 13:15:05') returning id
Questo costrutto PostgreSQL returning id
permette al comando insert
di restituire all’utente il valore per id scelto dal DBMS.
In MySQL invece abbiamo il modificatore auto_increment
per gli attributi:
create table Prenotazione (
id integer not null auto_increment,
istante timestamp not null,
primary key (id)
);
E per inserire ennuple usiamo:
insert into Prenotazione(istante) values ('2011-08-24 13:15:05')