Implementazione

Definizione SQL dello schema della base di dati


Note generali

Durante l'implementazione dello schema della base di dati in SQL è stato necessario effettuare alcune scelte. Per commentarle, si farà qui riferimento alla documentazione dello schema ER, nella quale si era data un'indicazione sui domini degli attributi.

Tipi enumerati

In fase di progettazione concettuale, era emersa la necessità di assegnare ad alcuni attributi un dominio costituito da un elenco di valori. Per la breve discussione seguente faremo riferimento, come esempio, all'attributo LAVORO.Tipo. Questo attributo poteva assumere uno tra i seguenti valori: Sebbene sia possibile definire con SQL domini personalizzati, si è ritenuto di assegnare a questi attributi il dominio INTEGER, con un vincolo CHECK per garantire che il valore introdotto sia maggiore di 0. Nell'esempio specifico:
CREATE TABLE Lavoro
(
[...]
Tipo INTEGER NOT NULL CHECK (Tipo > 0),
[...]
)

L'associazione tra i numeri interi positivi e le stringhe che descrivono il valore dell'attributo è demandata all'applicazione. Questo permette una notevole flessibilità: qualora, in futuro, il committente decidesse di introdurre altre categorie supplementari di lavoro, non sarebbe necessario modificare lo schema della base di dati. Inoltre la rappresentazione è più compatta e le espressioni SQL di manipolazione risultano più semplici.

Tipi monetari

Si è optato per l'utilizzo di campi DECIMAL (9, 2), con nove cifre per l'importo in euro e due cifre per i centesimi.

Vincoli di integrità

Sebbene il DBMS da noi scelto, PostgreSQL, non supporti le clausole ASSERTION, abbiamo incluso la codifica dei vincoli di integrità anche nell'implementazione SQL dello schema della base di dati.

Schema

CREATE TABLE Cliente
(
PartitaIVA VARCHAR (16) PRIMARY KEY,
RagioneSociale VARCHAR (50) NOT NULL,
Via VARCHAR (50),
CAP CHAR (5),
Comune VARCHAR (30),
Provincia CHAR (2),
Stato VARCHAR (14),
Telefono VARCHAR (14),
Fax VARCHAR (14),
EMail VARCHAR (40),
Note TEXT
);

CREATE TABLE Operatore
(
Codice VARCHAR (15) PRIMARY KEY,
Nome VARCHAR (20) NOT NULL,
Cognome VARCHAR (20) NOT NULL,
CostoOrario DECIMAL (9, 2) NOT NULL,
Attivo BOOLEAN NOT NULL,
Note TEXT
);

CREATE TABLE SchemaElettrico
(
Codice VARCHAR (30) PRIMARY KEY,
NomeFile VARCHAR (30),
Progettista VARCHAR (30),
Note TEXT
);

CREATE TABLE TipoDiArticolo
(
Codice SERIAL PRIMARY KEY,
Nome VARCHAR (50) NOT NULL,
Descrizione TEXT,
TensioneAlimentazione VARCHAR (15),
SchemaElettrico VARCHAR (30) NOT NULL
REFERENCES SchemaElettrico (Codice)
ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE Articolo
(
Matricola SERIAL PRIMARY KEY,
TipoArticolo INTEGER NOT NULL
REFERENCES TipoDiArticolo (Codice)
ON DELETE RESTRICT ON UPDATE CASCADE,
Cliente VARCHAR (16)
REFERENCES Cliente (PartitaIVA)
ON DELETE RESTRICT ON UPDATE CASCADE,
Note TEXT
);

CREATE TABLE Lavoro
(
Codice SERIAL PRIMARY KEY,
Tipo INTEGER NOT NULL CHECK (Tipo > 0),
DataInizioPrevista DATE NOT NULL,
DataTerminePrevista DATE NOT NULL,
Preventivo DECIMAL (9, 2),
OrePrevisteLavoro INTERVAL,
Priorita INTEGER NOT NULL CHECK (Priorita > 0),
StatoEsecuzione INTEGER NOT NULL CHECK (StatoEsecuzione > 0),
Prezzo DECIMAL (9, 2),
DataInizio DATE,
DataTermine DATE,
Responsabile VARCHAR (15) NOT NULL
REFERENCES Operatore (Codice)
ON DELETE RESTRICT ON UPDATE CASCADE,
Articolo INTEGER NOT NULL
REFERENCES Articolo (Matricola)
ON DELETE RESTRICT ON UPDATE CASCADE
);

CREATE TABLE Assegnazione
(
Operatore VARCHAR (15)
REFERENCES Operatore (Codice),
Lavoro INTEGER
REFERENCES Lavoro (Codice),
OreInterneOrdinarie INTERVAL NOT NULL,
OreEsterneOrdinarie INTERVAL NOT NULL,
OreInterneStraordinarie INTERVAL NOT NULL,
OreEsterneStraordinarie INTERVAL NOT NULL,

PRIMARY KEY (Operatore, Lavoro)
);
CREATE TABLE NonConformitaEst
(
Codice SERIAL PRIMARY KEY,
Lavoro INTEGER NOT NULL
REFERENCES Lavoro (Codice)
ON DELETE CASCADE ON UPDATE CASCADE,
Tipo INTEGER NOT NULL CHECK (Tipo > 0),
Note TEXT
);

CREATE TABLE NonConformitaInt
(
Codice SERIAL PRIMARY KEY,
Lavoro INTEGER NOT NULL
REFERENCES Lavoro (Codice)
ON DELETE CASCADE ON UPDATE CASCADE,
Tipo INTEGER NOT NULL CHECK (Tipo > 0),
OreDedicate INTERVAL NOT NULL,
Note TEXT
);

CREATE ASSERTION ResponsabileAssegnatoLavoro CHECK
(
EXISTS
(
SELECT *
FROM
LAVORO JOIN ASSEGNAZIONE
ON LAVORO.Codice = ASSEGNAZIONE.Lavoro
WHERE LAVORO.Responsabile = ASSEGNAZIONE.Operatore
)
);

CREATE ASSERTION ArticoloMontaggio CHECK
(
1 =
(
SELECT COUNT (*)
FROM
LAVORO JOIN ARTICOLO
ON LAVORO.Articolo = ARTICOLO.Matricola
WHERE LAVORO.Tipo = 1
)
);
CREATE ASSERTION OperatoreAssegnatoAttivo CHECK
(
0 =
(
SELECT COUNT (*)
FROM
OPERATORE JOIN ASSEGNAZIONE JOIN LAVORO
ON
ASSEGNAZIONE.Operatore = OPERATORE.Codice AND
ASSEGNAZIONE.Lavoro = Lavoro.Codice
WHERE OPERATORE.Attivo = FALSE AND LAVORO.StatoEsecuzione <> 3
)
);