12
Pagina 1 A. Veneziani – Analisi e svolgimento simulazione 2019 Febbraio (Informatica) Studio del testo Il problema indicato prospetta la completa gestione si hardware (prevalentemente riguardante Sistemi e Reti) sia software (in gran parte riguardante Informatica) di un sistema di noleggio di biciclette. Il sistema utilizzando moderne tecniche di identificazione , tracciamento delle presenze ed altro consentiti da moderni dispositivi elettronici, permette di tenere sotto controllo la situazione del posizionamento delle bici nelle varie stazioni di raccolta in modo automatico. Come riporta il testo possiamo identificare come soggetti di interesse dell’organizzazione software del noleggio, quelli più scontati: a) Le biciclette, considerate singolarmente con un ben preciso id b) Le stazioni c) Gli utenti che noleggiano o riportano le bici Infine ai fini di una organizzazione opportuna del DB e della registrazione di tutti gli spostamenti delle bici stesse, di devono considerare ovviamente le singole operazioni appunto di noleggio e ritorno delle bici. Una operazione di questo tipo è facile capire ha cinque parametri fondamentali: 1) Il momento in cui è stata effettuata (data e tempo) 2) Il tipo di operazione (noleggio o ritorno) 3) In quale stazione è avvenuta 4) Chi l’ha effettuata (ossia lo specifico utente) 5) Quale bicicletta ha coinvolto Centrale allo schema del DB sta quindi l’entità che potremmo chiamare Operazioni e che combina le altre. I dati strategici prima citati (momento dell’operazione (dataora) e tipo dell’operazione) contenuti in tale entità ci permettono già di organizzare i dati di modo da rispondere a tutte le richieste poste nel testo del compito d’esame ai punti 2, 3a e 3b, e nella seconda parte, i punti I, IIa e IIb. Progettazione del DB – Punto 2 della traccia Per le considerazioni prima esposte, dovremo considerare il DB costituito da almeno 4 entità le quali saranno: Utenti Biciclette Stazioni Operazioni (preposta a memorizzare le varie operazioni di noleggio e ritorno) Gli attributi che potremo prevedere per ciascuno di esse saranno: Entità Utenti Nome attributo Scopo Codice fiscale Codice fiscale dell’utente – attributo chiave Numero carta Numero della carta di credito Nome Nome dell’utente Cognome Cognome dell’utente Via Via di residenza dell’utente NCiv Numero civico di residenza Citta Città di residenza Telefono Telefono dell’utente (fisso o cellulare) Mail Indirizzo mail dell’utente Entità Biciclette Nome attributo Scopo

A. Veneziani Analisi e svolgimento simulazione 2019 ... · Pagina 2 Id bicicletta Identificativo della bicicletta – attributo chiave Data inizio servizio Da di ingresso in servizio

Embed Size (px)

Citation preview

Pagina 1

A. Veneziani – Analisi e svolgimento simulazione 2019 Febbraio (Informatica)

Studio del testo

Il problema indicato prospetta la completa gestione si hardware (prevalentemente riguardante Sistemi e

Reti) sia software (in gran parte riguardante Informatica) di un sistema di noleggio di biciclette.

Il sistema utilizzando moderne tecniche di identificazione , tracciamento delle presenze ed altro consentiti

da moderni dispositivi elettronici, permette di tenere sotto controllo la situazione del posizionamento delle

bici nelle varie stazioni di raccolta in modo automatico.

Come riporta il testo possiamo identificare come soggetti di interesse dell’organizzazione software del

noleggio, quelli più scontati:

a) Le biciclette, considerate singolarmente con un ben preciso id

b) Le stazioni

c) Gli utenti che noleggiano o riportano le bici

Infine ai fini di una organizzazione opportuna del DB e della registrazione di tutti gli spostamenti delle bici

stesse, di devono considerare ovviamente le singole operazioni appunto di noleggio e ritorno delle bici.

Una operazione di questo tipo è facile capire ha cinque parametri fondamentali:

1) Il momento in cui è stata effettuata (data e tempo)

2) Il tipo di operazione (noleggio o ritorno)

3) In quale stazione è avvenuta

4) Chi l’ha effettuata (ossia lo specifico utente)

5) Quale bicicletta ha coinvolto

Centrale allo schema del DB sta quindi l’entità che potremmo chiamare Operazioni e che combina le altre.

I dati strategici prima citati (momento dell’operazione (dataora) e tipo dell’operazione) contenuti in tale

entità ci permettono già di organizzare i dati di modo da rispondere a tutte le richieste poste nel testo del

compito d’esame ai punti 2, 3a e 3b, e nella seconda parte, i punti I, IIa e IIb.

Progettazione del DB – Punto 2 della traccia

Per le considerazioni prima esposte, dovremo considerare il DB costituito da almeno 4 entità le quali saranno:

Utenti

Biciclette

Stazioni

Operazioni (preposta a memorizzare le varie operazioni di noleggio e ritorno)

Gli attributi che potremo prevedere per ciascuno di esse saranno:

Entità Utenti

Nome attributo Scopo

Codice fiscale Codice fiscale dell’utente – attributo chiave

Numero carta Numero della carta di credito

Nome Nome dell’utente

Cognome Cognome dell’utente

Via Via di residenza dell’utente

NCiv Numero civico di residenza

Citta Città di residenza

Telefono Telefono dell’utente (fisso o cellulare)

Mail Indirizzo mail dell’utente

Entità Biciclette

Nome attributo Scopo

Pagina 2

Id bicicletta Identificativo della bicicletta – attributo chiave

Data inizio servizio Da di ingresso in servizio della bicicletta

Km Km complessivi percorsi dalla bici

Entità Stazioni

Nome attributo Scopo

IdStazione Codice identificativo della stazione – attributo chiave

Via Via dove è situata la stazione

NCiv Numero civico

Entità Operazioni

Nome attributo Scopo

IdOpe Codice identificativo della operazione (di noleggio o ritorno) – attributo chiave

Tipo Tipo dell’operazione (noleggio o ritorno N o R)

Momento Momento in cui avviene l’operazione considerata

Le associazioni

Le associazioni tra le entità considerate sono piuttosto intuitive da immaginare. Nel diagramma l’entità

Operazioni è centrale e collegata con le altre, in quanto nel modello supposto ogni operazione, è in relazione

con un cliente che la esegue (il cliente riporta o prende una bicicletta), con una bicicletta (dato che è essa

l’oggetto del noleggio) e con una stazione (quella ove avviene la singola operazione di noleggio o reso.

Quindi avremo tre associazioni che vanno da Operazioni a Utenti, a Biciclette e a Stazioni.

La molteplicità di tali associazioni è 1 a n, con n rivolto verso Operazioni per tutte e 3 le associazioni. Infatti

ad utente corrispondono più operazioni, ma ad una operazione un solo utente che la svolge. Ad una bicicletta

corrispondono più operazioni svolte su essa, ma una operazione coinvolgerà solo una bici, ed in una stazione

si svolgono più operazioni, ma una operazione può essere svolta in una sola stazione.

La associazioni in linea di massima possono essere considerate totali, tranne eventualmente quelle di

Bicicletta verso Operazioni (perché potrebbe trattarsi di una bicicletta appena messa in servizio) e quella di

utenti verso Operazioni (perché potrebbe essere un utente appena registrato o che per ora non ha avuto

occasione di utilizzare il servizio).

Schema delle relazioni

Utenti(CF, NCarta, Nome, Cognome, Via, NCiv, Citta, Telefono, Mail)

Biciclette(IdBicicletta, DataInServ, Km)

Stazioni(IdStazione, Via, NCiv)

Operazioni(IdOpe, Tipo, Momento, CF, IdStazione, IdBici)

Relazioni in forma tabellare

Relazione Utenti

Nome campo Tipo Ampiezza NULL Chiavi

CF CHAR(16) 16 No Primaria

NCarta CHAR(20) 20 No

Nome VARCHAR(40) 40 No

Cognome VARCHAR(40) 40 No

Via VARCHAR(40) 40 No

NCiv CHAR(6) 6 No

Pagina 3

Citta VARCHAR(50) 50 No

Telefono VARCHAR(20) 20 No

Mail VARCHAR(30) 40 No

Relazione Biciclette

Nome campo Tipo Ampiezza NULL Chiavi

IdBicicletta INT UNSIGNED No Primaria

DataInServ DATE No

Km INT UNSIGNED No

Relazione Stazioni

Nome campo Tipo Ampiezza NULL Chiavi

IdStazione INT UNSIGNED No Primaria

Via VARCHAR(40) No

NCiv VARCHAR(6) No

Relazione Operazioni

Nome campo Tipo Ampiezza NULL Chiavi

IdOpe INT UNSIGNED No Primaria

Tipo ENUM(‘N’,’R’) No

Momento DATETIME No

CF CHAR(16) Si Esterna

IdStazione INT UNSIGNED No Esterna

IdBici INT UNSIGNED No Esterna

Script SQL di creazione del DB

CREATE TABLE Utenti (

CF CHAR(16) NOT NULL PRIMARY KEY,

NCarta CHAR(20) NOT NULL,

Nome VARCHAR(40) NOT NULL,

Cognome VARCHAR(40) NOT NULL,

Via VARCHAR(50) NOT NULL,

NCiv CHAR(6) NOT NULL,

Citta VARCHAR(50) NOT NULL,

Telefono VARCHAR(20) NOT NULL,

Mail VARCHAR(30) NOT NULL );

CREATE TABLE Stazioni (

IdStazione INT UNSIGNED PRIMARY KEY,

Via VARCHAR(40) NOT NULL,

NCiv CHAR(6) NOT NULL );

CREATE TABLE Biciclette (

IdBici INT UNSIGNED PRIMARY KEY,

DataInServ DATE NOT NULL,

Km INT UNSIGNED NOT NULL );

CREATE TABLE Operazioni (

Pagina 4

IdOpe INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

Tipo ENUM('N','R') NOT NULL,

Momento DATETIME NOT NULL,

CF CHAR(16),

IdStazione INT UNSIGNED NOT NULL,

IdBici INT UNSIGNED NOT NULL,

FOREIGN KEY(CF) REFERENCES Utenti(CF),

FOREIGN KEY(IdStazione) REFERENCES Stazioni(IdStazione),

FOREIGN KEY(IdBici) REFERENCES Biciclette(IdBici) );

Diagramma UML del DB

Punto 3° della traccia

Tralasciando di indicare come generare la mappa delle stazioni in forma grafica, essa una volta creata

potrebbe agire come mappa sensibile Web. Praticamente con vari meccanismi alla fine potremo ottenere

l’id (corrispondente a quello registrato nel DB come chiave primaria della tabella stazioni), di una stazione

selezionata e poi svolgere quanto richiede il quesito, ossia capire se nella stazione vi sono biciclette disponibili

per il noleggio.

Per semplificare invece della mappa ho realizzato una pagina con un selettore a discesa elencante tutte le

varie stazioni, di cui solo una potrà essere selezionata.

La generazione della lista delle stazioni e la gestione della stessa (ricarico automatico del valore selezionato)

è riportata in grigio.

A questo punto effettueremo due ricerche in cascata:

1) Nella prima individueremo per ogni bicicletta il momento dell’ultima operazione svolta su di essa:

Pagina 5

SELECT biciclette.IdBici, MAX(Momento)

FROM operazioni, biciclette

WHERE

operazioni.IdBici = biciclette.IdBici

GROUP BY biciclette.IdBici;

2) Nella seconda, basandosi sui risultati della prima operazione (1), considereremo solo i dati

dell’ultima operazione svolta su una certa bicicletta e solo se accaduta nella stazione di interesse:

SELECT *

FROM stazioni, operazioni, biciclette

WHERE

stazioni.IdStazione = operazioni.IdStazione AND

operazioni.IdBici = biciclette.IdBici AND

biciclette.IdBici = <id della bici>

AND stazioni.IdStazione = <id della stazione>

AND Momento = <ultima operazione della bici con l'id considerato>

3) Per ogni risultato ammissibile capiremo se esso sia di tipo ‘R’ (rientro).

Effettuando un conteggio sui risultati di questa ultima condizione (3), potremo capire il numero delle

biciclette presenti nella stazione stessa (numero delle bicilette che hanno come ultima operazione un

rientro nella stazione x).

La pagina PHP che realizza questo (basandosi sul DB proposto) è:

<html>

<head>

<title>Simulazione 2019 Febbraio punto 3a</title>

</head>

<body>

<form action="pagina_3a.php" method="post">

Stazione:

<select name="stazioni">

<?php

// connessione e selezione del DB

$conn = mysqli_connect("localhost","root","")

or die("Connessione fallita.");

mysqli_select_db($conn, "simulazione_2019_feb")

or die("Db selezionato non esistente.");

// estrazione della lista delle stazioni

$rs3 = mysqli_query($conn, "SELECT * FROM Stazioni");

$riga3 = mysqli_fetch_array($rs3);

while ($riga3)

{

$sele = "";

if ($_POST)

{

if ($_POST['stazioni'] == $riga3['IdStazione'])

$sele = "selected";

else

$sele = "";

}

echo '<option value="' . $riga3['IdStazione'] . '" ' . $sele . '>' . $riga3['Via'] .

"</option>";

Pagina 6

$riga3 = mysqli_fetch_array($rs3);

}

?>

</select>

<br>

<input type="submit" value="Indica bici presenti">

</form>

<?php

if ($_POST)

{

// individua il momento in cui è avvenuta l'ultima operazione su una bici (in una certa

stazione)

// individua il momento in cui è avvenuta l'ultima operazione su una bici

$rs = mysqli_query($conn, "SELECT biciclette.IdBici, MAX(Momento) As UltimoEvento " .

"FROM operazioni, biciclette " .

"WHERE " .

"operazioni.IdBici = biciclette.IdBici " .

" GROUP BY biciclette.IdBici");

$riga = mysqli_fetch_array($rs);

$bicidisp = 0;

while ($riga)

{

$rs2 = mysqli_query($conn, "SELECT * " .

"FROM stazioni, operazioni, biciclette " .

"WHERE " .

"stazioni.IdStazione = operazioni.IdStazione AND " .

"operazioni.IdBici = biciclette.IdBici AND " .

"biciclette.IdBici = " . $riga['IdBici'] .

" AND stazioni.IdStazione = " . $_POST['stazioni']

. " AND Momento = '" . $riga['UltimoEvento'] . "'");

$riga2 = mysqli_fetch_array($rs2);

if ($riga2['Tipo'] == "R") $bicidisp++;

$riga = mysqli_fetch_array($rs);

}

echo "La stazione ha " . $bicidisp . " bici disponibili in questo momento.";

}

?>

</body>

</html>

La cui parte effettivamente operativa riguardo

al problema posto è quella evidenziata in

azzurro.

Punto 3b della traccia

Il punto 3b chiede di conoscere quali siano le

bici attualmente in uso, quale utente sia ad

usarle, e da quale stazione siano partite.

Considerando sempre il criterio dell’ultima operazione effettuata su una bici, le bici attualmente in uso sono

individuabili:

1) Individuando l’ultima operazione svolta su ogni bici

SELECT biciclette.IdBici, MAX(Momento) As UltimoEvento

Pagina 7

FROM stazioni, operazioni, biciclette

WHERE

operazioni.IdBici = biciclette.IdBici

GROUP BY biciclette.IdBici

2) Scandendo tali ultime operazioni: se essa risulti di tipo ‘N’, la bici risulta in uso (ossia in noleggio)

si va a ricavare chi l’abbia noleggiata e da quale stazione provenga

SELECT *, stazioni.Via As Via_

FROM stazioni, operazioni, biciclette, utenti

WHERE

stazioni.IdStazione = operazioni.IdStazione AND

operazioni.IdBici = biciclette.IdBici AND

operazioni.CF = utenti.CF AND

biciclette.IdBici = <id della bici considerata>

AND Momento = <ultima operazione svolta su quella bici>

In questo caso l’operazione di ricerca è del tutto generale, quindi non vi sono input per la pagina che la

effettua. Essa ricerca in generale su tutte le biciclette se l’ultima operazione sia del tipo “noleggio” e quindi

deduce che tale biciletta sia in noleggio, ricavandone utente noleggiante e stazione da cui sia stata

noleggiata.

<html>

<head>

<title>Simulazione 2019 Febbraio punto 3b</title>

</head>

<body>

<b>Elenco delle bici in uso:</b><br>

<?php

// connessione e selezione del DB

$conn = mysqli_connect("localhost","root","")

or die("Connessione fallita.");

mysqli_select_db($conn, "simulazione_2019_feb")

or die("Db selezionato non esistente.");

// individua il momento in cui è avvenuta l'ultima operazione su una bici (in una certa

stazione)

$rs = mysqli_query($conn, "SELECT biciclette.IdBici, MAX(Momento) As UltimoEvento " .

"FROM stazioni, operazioni, biciclette " .

"WHERE " .

"operazioni.IdBici = biciclette.IdBici " .

" GROUP BY biciclette.IdBici");

$riga = mysqli_fetch_array($rs);

$bici_circo = 0;

while ($riga)

{

$rs2 = mysqli_query($conn, "SELECT *, stazioni.Via As Via_ " .

"FROM stazioni, operazioni, biciclette, utenti " .

"WHERE " .

"stazioni.IdStazione = operazioni.IdStazione AND " .

"operazioni.IdBici = biciclette.IdBici AND " .

"operazioni.CF = utenti.CF AND " .

"biciclette.IdBici = " . $riga['IdBici'] .

" AND Momento = '" . $riga['UltimoEvento'] . "'");

Pagina 8

$riga2 = mysqli_fetch_array($rs2);

if ($riga2['Tipo'] == "N")

{

$bici_circo++;

echo "La bicicletta " . $riga['IdBici'] .

" è in uso a " . $riga2['Nome'] . " " . $riga2['Cognome'] .

" ed è stata prelevata dalla stazione di " . $riga2['Via_'] . "<br>";

}

$riga = mysqli_fetch_array($rs);

}

echo "Le bici circolanti sono in

numero " . $bici_circo;

?>

</body>

</html>

Svolgimento punto I della traccia

Possiamo considerare che con il disegno del DB

considerato, selezionato un certo utente e

ordinate le operazioni secondo il tempo in cui sono accadute, le operazioni dovrebbero presentarsi, in una

situazione normale, come una serie di operazioni di tipo N e poi R, su stazioni differenti o uguali.

La durata del singolo noleggio si può quindi dedurre dal tempo trascorso tra una operazione N e la operazione

subito successiva R. Questa coppia di operazioni impegnerà peraltro, ovviamente, la stessa bicicletta (quella

utilizzata per il noleggio).

Si tratta quindi di analizzare per lo specifico utente le coppie di operazioni di questo tipo e dedurne i dati

richiesti dalla traccia.

Qui riporto una soluzione relativa ad un sistema a pagine Web.

La prima pagina preparata roduce la lista degli utenti, dei quali si desidera avere il report.

Il link alla seconda pagina è integrato al passaggio verso la pagina stessa di un valore passato come parametro

sulla linea degli indirizzi:

<html>

<head>

<title>Simulazione 2019 Febbraio punto I (lista clienti)</title>

</head>

<body>

<?php

// connessione e selezione del DB

$conn = mysqli_connect("localhost","root","")

or die("Connessione fallita.");

mysqli_select_db($conn, "simulazione_2019_feb")

or die("Db selezionato non esistente.");

$rs = mysqli_query($conn, "SELECT * FROM Utenti");

?>

<table>

<tr><td><b>Codice fiscale</b></td><td><b>Nome</b></td><td><b>Cognome</b></td></tr>

<?php

$riga = mysqli_fetch_array($rs);

while ($riga)

{

Pagina 9

echo '<tr><td><a href="pagina_punto_I.php?cf=' . $riga['CF'] . '">' . $riga['CF'] .

'</a></td><td>' . $riga['Nome'] . '</td><td>' . $riga['Cognome'] . '</td></tr>';

$riga = mysqli_fetch_array($rs);

}

?>

</body>

</html>

La pagina più importante e critica tuttavia è

ovviamente quella che compone il report vero e

proprio.

Essa si compone di una query che individua tutte

le operazioni dell’utente in questione, mettendole

in più in ordine di tempo. Come già considerato,

due operazioni di noleggio e rientro per uno stesso

utente avranno la caratteristica di essere:

Contigue se i record sono ordinati

temporalmente

Avere una operazione di tipo N prima e una

operazione di tipo R a seguire

Temporalmente non ci saranno altre

operazioni interne all’intervallo per quell’utente

(l’utente ha già una bicicletta in noleggio).

La bicicletta nelle due operazioni sarà la medesima

Si noti che eventuali operazioni N o R di natura diversa (spostamenti da parte della società di gestione) sono

automaticamente escluse da questa lista in quanto con campo CF a valore NULL.

Successivamente nella scansione dei record risultanti vi possono essere 3 situazioni ammissibili (altre

combinazioni sono da escludere perché presupporebbero una incoerenza nel DB):

Il numero di record è pari e ovviamente i record di tipo N ed R delle operazioni sono correttamente

alternati temporalmente (ad esempio N -> R -> N -> R). Ci troviamo nel caso di una serie di noleggi

tutti già conclusi.

Il numero di record è dispari e pur seguendo la solita sequenza (N -> R -> N -> R -> N) la catena finisce

con un record con tipo N. Questa situazione sta ad indicare che l’utente ha un noleggio in corso.

Ultima evenienza è che l’utente non abbia ancora noleggiato nulla e quindi in operazioni non si

trovano record correlati al suo codice fiscale.

Detto questo la pagina opera:

a) Individuando il primo record N e registrando il momento di inizio del noleggio

b) Passando poi al record successivo

c) Controllando se il record successivo:

1. Non esista (allora deduco che è una operazione di noleggio in corso)

2. Esista e quindi sarà di tipo R (e quindi è una operazione di noleggio conclusa)

d) Rilevo anche in questo ultimo caso il tempo di fine noleggio (caso 2) od il tempo corrente attuale

(caso 1)

e) Effettuerò poi un delta tra i tempi da calcolare in ore

f) Dato il costo orario del noleggio (nel nostro esempio inserito nel codice della pagina) è possibile

ricavare il costo del singolo noleggio.

g) Un opportuno accumulatore permette di calcolare anche il costo totale di tutti i noleggi.

Le operazioni particolari utilizzate nella pagina sono:

Pagina 10

La generazione della data ed ora corrente tramite la funzione date(…)1

la conversione di un dato in formato data + tempo in forma di testo, da testo ad un valore intero in

secondi in PHP tramite la funzione strtotime(….)2

l’esecuzione di una operazione di differenza di tempi tramite il comune operatore di sottrazione

infine la conversione ad ore del valore differenza che è espresso ancora in secondi (tramite la

semplice considerazione che un ora è formata da 3600 secondi).

l’uso della funzione number_format(…)3 per formattare gli output double in formato con virgola fissa

a 2 decimali e la virgola come separatore

<html>

<head>

<title>Simulazione 2019 Febbraio punto I (report)</title>

</head>

<body>

<?php

define("PREZZO_ORA",0.5); // prezzo per ora implementato nel codice della pagina

// connessione e selezione del DB

$conn = mysqli_connect("localhost","root","")

or die("Connessione fallita.");

mysqli_select_db($conn, "simulazione_2019_feb")

or die("Db selezionato non esistente.");

// la query trova la sequenza di operazioni ordinata nel tempo di un

// certo utente. Le operazioni dovrebbero alternarsi con tipo

// N / R / N / R e cosi' via...

// Se l'ultima operazione è di tipo N un noleggio è ancora in corso...

$rs = mysqli_query($conn, "SELECT * " .

"FROM stazioni, operazioni, biciclette, utenti " .

"WHERE " .

"stazioni.IdStazione = operazioni.IdStazione AND " .

"operazioni.IdBici = biciclette.IdBici AND " .

"operazioni.CF = utenti.CF AND " .

"utenti.CF = '" . $_GET['cf'] . "' " .

"ORDER BY Momento");

$riga = mysqli_fetch_array($rs);

$nessuno = true;

$totale = 0;

while ($riga)

{

echo "<br><br>";

// se il record corrente e' di tipo "noleggio" (N)

if ($riga['Tipo'] == 'N')

{

// memorizza il tempo di inizio noleggio

$tinizio = $riga['Momento'];

$t1 = strtotime($tinizio);

echo "inizio noleggio il " . $tinizio . "<br>";

// passa al record successivo (immediatamente successivo) in ordine di tempo

1 http://php.net/manual/en/function.date.php 2 http://php.net/manual/en/function.strtotime.php 3 http://php.net/manual/en/function.number-format.php

Pagina 11

$riga = mysqli_fetch_array($rs);

}

// se il record successivo e' di tipo R (rientro dal noleggio)

if ($riga['Tipo'] == 'R')

{

// memorizza il tempo di fine noleggio

$tfine = $riga['Momento'];

$t2 = strtotime($tfine);

echo "fine noleggio il " . $tfine . "<br>";

}

// se il record successivo non esiste ....

if (! $riga)

{

echo "Ultimo noleggio ancora in corso...<br>";

// genera una stringa (nel formato indicato) contenente il tempo corrente

$adesso = date('Y-m-d H:i:s');

$t2 = strtotime($adesso);

}

// calcola la differenza dei tempi di noleggio (in secondi)

$diff = $t2 - $t1;

// calcolo il delta in ore e ne aggiungo una di default (la prima)

$ore_noleggio = ((int) ($diff / (60 * 60))) + 1;

echo "Ore di durata del noleggio: " . $ore_noleggio . "<br>";

$spesa = PREZZO_ORA * $ore_noleggio;

echo "Spesa per il noleggio: " . number_format($spesa,2,",",".") . "<br>";

$totale = $totale + $spesa; // calcolo con accumulo della spesa totale

$riga = mysqli_fetch_array($rs);

$nessuno = false;

}

if ($nessuno) echo "Nessun noleggio effettuato.";

echo "<br><br>Totale spesa noleggi: " .

number_format($totale,2,",",".");

?>

</body>

</html>

L’invio periodico del report presuppone un applicativo che

riesca a effettuare l’operazione in momenti determinati. Si

potrebbe ad esempio pensare ad uno script PHP (per rimanere

nell’ambito dello stesso linguaggio) di tipo console che sia

lanciato e giri sul server, e lo stesso legga ripetutamente il

tempo corrente di sistema ad intervalli di tempo laschi.

L’operazione potrebbe essere realizzata con un ritardo lungo

ed un ciclo infinito. Al momento che il valore del mese letto cambia, si dovrebbe eseguire una parte di codice

che, composto il report, generato con metodi simili a quelli applicati nelle pagine Web qui sopra, lo cumuli in

una stringa e lo immetta in una operazione di invio mail verso il relativo cliente (comando PHP mail(…)).

Il DB tra l’altro mette a disposizione anche l’indirizzo mail del cliente stesso, proprio per permettere questa

operazione in modo del tutto automatico.

In questo modo i report, ad ogni inizio mese verrebbero erogati a tutti i clienti via mail in modo

contemporaneo, tramite un ulteriore ciclo che scansisca tutti gli utenti, in rapida successione.

Pagina 12

Svolgimento punti IIa e IIb

Si tratta di due classiche query sul DB richieste per risolvere i problemi indicati:

a) Dato il codice di una bicicletta elencare gli utenti che l’hanno utilizzata nel mese corrente.

Si noti che MONTH isola in un dato datetime SQL il solo valore del mese e che il mese corrente può essere

facilmente ricavato grazie alla importante funzione NOW() che produce appunto un datetime col tempo

corrente (la query ipotizza di testare gli utilizzi della bici di id 3):

SELECT DISTINCT utenti.*

FROM biciclette, operazioni, utenti

WHERE

biciclette.IdBici = operazioni.IdBici AND

operazioni.CF = utenti.CF AND

biciclette.IdBici = 3 AND

MONTH(NOW()) = MONTH(Momento);

b) Mostrare la stazione presso la quale è stato effettuato il maggior numero di noleggi in un dato

periodo.

CREATE OR REPLACE VIEW Noleggi AS

SELECT stazioni.IdStazione, stazioni.Via, COUNT(*) AS NumNoleggi

FROM stazioni, operazioni

WHERE

stazioni.IdStazione = operazioni.IdStazione AND

operazioni.Tipo = 'N' AND

Momento BETWEEN '2019-01-01' AND '2019-12-31'

GROUP BY stazioni.IdStazione;

in questa seconda query si crea una view che individua tutti i noleggi nel periodo desiderato e li raggruppa

per stazione contando il loro numero.

Resta però da determinare su quale stazione sia stato effettuato il maggior numero di noleggi.

Questo può essere fatto utilizzando la tabella dei dati creati dalla view e cercando in essa il massimo valore

di noleggi. Successivamente sempre sulla stessa view Noleggi si andranno a selezionare solo i record (ed il

relativo dato delle stazioni) che presentano quel numero di noleggi (ossia il massimo) e non altri:

SELECT IdStazione, Via, NumNoleggi

FROM Noleggi

WHERE NumNoleggi =

(SELECT MAX(NumNoleggi)

FROM Noleggi);