Il tema proposto è frutto della modalità di esame scelta dal Ministero che prevede una seconda prova proposta dalla commissione interna di esame in base all’esperienza maturata dagli alunni durante l’anno scolastico. Quindi ogni commissione di ogni scuola ne avrà prodotta una diversa. Proponiamo la soluzione della prova svolta all’IIS Alessandrini Marino di Teramo, prova significativa che può essere usata come simulazione o esercitazione per le prove di esame ministeriali uniche, qualora si riproponessero negli anni futuri. Come solito nelle nostre soluzioni, offriamo spunti di riflessione alla soluzione che non necessariamente è l’unica o la più corretta in senso assoluto.
Il candidato svolga la prima parte della prova e risponda a due, a scelta, tra i quesiti proposti nella seconda parte.
Indice dei contenuti
Prima parte
La regione Abruzzo, nell’ottica di razionalizzare la spesa sanitaria, ha promosso la realizzazione di un sistema informativo per poter analizzare i dati derivanti dai ricoveri effettuati nelle varie strutture ospedaliere (pubbliche e/o private) dislocate sul territorio.
Ciascuna struttura appartiene ad una delle quattro AUSL in cui la regione è suddivisa (AUSL n.01-L’Aquila / AUSL n.02-Chieti, Lanciano, Vasto / AUSL n.03-Pescara / AUSL n.04-Teramo).
Di ogni struttura ospedaliera occorre memorizzare il codice, il nome, l’indirizzo, la città, la provincia, la AUSL di appartenenza, il tipo di struttura (se pubblica o privata). Di ciascun ricovero effettuato dalle varie strutture devono essere memorizzati: la data di inizio, la data di fine, la causa del ricovero. Deve, inoltre, contenere informazioni riguardo all’unità operativa in cui è avvenuta la degenza, al paziente coinvolto e agli eventuali interventi che sono stati effettuati.
Le unità operative sono classificate tramite un codice ed una descrizione (ad es. Medicina, Diabetologia, Ostetricia e Ginecologia, Ematologia, Terapia intensiva, Urologia ecc.). I pazienti sono identificati dal codice fiscale, cognome, nome, data di nascita, genere (M/F), indirizzo, città, provincia di residenza, recapito telefonico. Gli interventi sono classificati con codice, descrizione e costo.
Il candidato, fatte le opportune ipotesi aggiuntive, commentando e motivando adeguatamente le scelte effettuate, sviluppi:
- un analisi della realtà di riferimento, giungendo alla definizione di uno schema concettuale della basi di dati che, a suo motivato giudizio, sia idoneo a gestire la realtà presentata;
- il relativo schema logico;
- il codice SQL per la definizione di almeno 3 tabelle collegate tra loro;
- le seguenti interrogazioni in linguaggi SQL:
- Fornire l’elenco dei ricoveri in cui sono stati effettuati gli interventi di costo superiore a euro 2000.00
- Fornire l’elenco delle strutture ospedaliere private in ordine di provincia di appartenenza e, a parità di provincia, in ordine alfabetico di denominazione
- Visualizzare un elenco delle unità operative per cui risultino più di 100 ricoveri
- Fornire il numero di pazienti ricoverati causa COVID a partire da marzo 2020
- la progettazione dell’interfaccia della/e pagina/e web e la loro realizzazione, con appropriati linguaggi a scelta sia lato client che lato server, di un segmento significativo dell’applicazione Web che consenta l’interazione con la base di dati.
Seconda parte
Il candidato risponda a due quesiti a scelta tra quelli sotto riportati
- In relazione al tema proposto nella prima parte, il candidato descriva in che modo è possibile integrare il solo schema concettuale sopra sviluppato in modo da poter gestire la possibilità di gestire i dipendenti delle varie strutture ospedaliere per i quali si richiede la memorizzazione di: dati anagrafici, ruolo(Medico/Infermiere/Amministrativo), contatto telefonico per la reperibilità
- Il candidato illustri le categorie di linguaggio messe a disposizione di un DBMS specificandone le funzioni. Indichi, poi, a quale categoria di linguaggio appartengono i comandi DROP TABLE e DELETE FROM TABLE fornendo anche gli opportuni esempi
- Il candidato esponga le regole di derivazione che permettono di passare dal modello concettuale al modello logico
- Si consideri il seguente modello relazionale
- contratti(Codice, Descrizione, StipendioBase, DataScadenza)
- dipendenti(Matricola, Cognome, Nome, DataAssunzione, FK_Codice) di un database per la memorizzazione dei dati dei dipendenti di un’azienda e del contratto di lavoro di riferimento in cui Matricola e Codice sono chiavi primarie, FK_Codice è una chiave esterna.
- Risalire allo schema E/R da cui deriva il modello logico fornito
- Esporre eventuali problemi che possono verificarsi se si vuole modificare nella tabella dei contratti il codice di un contratto e in che modo il DBMS ne permette la gestione
Soluzione proposta
La prova non presenta particolari difficoltà ma è sicuramente impegnativa per la lunghezza del lavoro da svolgere nelle 6 ore fornite ai candidati. Come sempre nelle tracce di esame, si consiglia di partire da una attenta lettura del testo non solo della specifica progettuale ma anche delle query e delle eventuali appendici negli esercizi della seconda parte che possono essere decisivi per comprendere alcune relazioni o dubbi sulle entità presenti poi nel modello concettuale da estrapolare. Prima di giungere infatti alla soluzione, verifichiamo che le query proposte siano realizzabili e abbiano legami di join rispondenti.
Proviamo ad individuare le entità principali: la AUSL, la struttura, unità operativa, ricovero, paziente. L’unico dubbio che può venire al candidato è sulla reale necessità dell’entità AUSL: nel testo infatti potrebbe facilmente confondersi come un attributo, magari enumerativo, dell’entità struttura. Qui la scelta progettuale tocca al candidato. E’ buona norma non abusare degli attributi enumerativi se non davanti a evidenze come il sesso M/F. Nel caso di AUSL infatti potrebbe esserci la necessità di descrivere ulteriormente la AUSL stessa in futuro necessitando, di fatto, di una tabella tutta sua. Qui aggiungiamo un attributo descrittivo.
Altra criticità, le unità operative. Qui sembrano le classica entità di gruppo con due campi codice/descrizione. In realtà diventa una entità significativa alla luce delle query richieste che ne chiariscono un ruolo importante.
Gli interventi consideriamo tali non solo le operazioni chirurgiche e simili, ma anche tutti i trattamenti farmacologici o simili.
Per semplicità, consideriamo i campi Città e Provincia come testuali semplici. In una base di dati realistica, probabilmente adotteremmo due tabelle Città e Provincia per avere una gestione dei dati incrementali.
Per ogni coppia struttura/unità operativa, potremmo prevedere attributi aggiuntivi come ad esempio i posti letto, il numero di interventi o altri servizi delle rispettive unità. Non essendo necessarie ai fini delle successive query, tralasciamo questi attributi che andrebbero segnati nel rombo di collegamento tra le due entità.
Modello concettuale
Modello logico
Lo schema logico risultante:
- AUSL(NomeAusl, Descrizione)
- Struttura(IDStruttura, Nome, Indirizzo, Città, Provincia, FK_NomeAusl)
- UnitaOperativa(IDUnita, Descrizione)
- UnitaOperativePerStrutture(ID, FK_IDStruttura, FK_IDUnita)
- Ricovero(IDRicovero, DataRicovero, DataDimissioni, FK_CF, FK_IDUnita)
- Paziente(CF, Nome, Cognome, DataNascita, Genere, Indirizzo, Città, Provincia, Telefono)
- Intervento(IDIntervento, Descrizone, Costo)
- InterventiPerRicoveri(ID, FK_IDRicovero, FK_IDIntervento)
Creazione tabelle
Scegliamo 3 tabelle consecutive e sviluppiamo il codice conseguente: AUSL, Struttura, UnitaOrganizzative e UnitaOperativePerStrutture
CREATE TABLE `AUSL` (
`NomeAUSL` varchar(60) NOT NULL,
`Descrizione` varchar(100) DEFAULT NULL,
PRIMARY KEY (`NomeAUSL`)
) ENGINE=InnoDB;
CREATE TABLE `Struttura` (
`IDStruttura` char(5) NOT NULL,
`Nome` varchar(60) NOT NULL,
`Indirizzo` varchar(100) NOT NULL,
`Città` varchar(60) NOT NULL,
`Provincia` char(2) NOT NULL,
`FK_NomeAusl` varchar(60) NOT NULL,
PRIMARY KEY (`IDStruttura`),
KEY `AUSL` (`FK_NomeAusl`)
) ENGINE=InnoDB;
CREATE TABLE `UnitaOperativa` (
`IDUnita` varchar(30) NOT NULL,
`Descrizione` varchar(60) NOT NULL,
PRIMARY KEY (`IDUnita`)
) ENGINE=InnoDB;
CREATE TABLE `UnitaOperativePerStrutture` (
`ID` int NOT NULL AUTO_INCREMENT,
`FK_IDStruttura` char(5) NOT NULL,
`FK_IDUnita` varchar(30) NOT NULL,
PRIMARY KEY (`ID`),
KEY `strutture` (`FK_IDStruttura`),
--
-- Limiti per la tabella `Struttura`
--
ALTER TABLE `Struttura`
ADD CONSTRAINT `AUSL` FOREIGN KEY (`FK_NomeAusl`) REFERENCES `AUSL` (`NomeAUSL`) ON DELETE RESTRICT ON UPDATE CASCADE;
--
-- Limiti per la tabella `UnitaOperativePerStrutture`
--
ALTER TABLE `UnitaOperativePerStrutture`
ADD CONSTRAINT `strutture` FOREIGN KEY (`FK_IDStruttura`) REFERENCES `Struttura` (`IDStruttura`) ON DELETE RESTRICT ON UPDATE CASCADE,
ADD CONSTRAINT `unitaoperative` FOREIGN KEY (`FK_IDUnita`) REFERENCES `UnitaOperativa` (`IDUnita`) ON DELETE RESTRICT ON UPDATE CASCADE;
COMMIT;
Queries
1. Fornire l’elenco dei ricoveri in cui sono stati effettuati gli interventi di costo superiore a euro 2000.00
SELECT *
FROM Ricovero, Intervento, InterventiPerRicoveri
WHERE Ricovero.IDRicovero = InterventiPerRicoveri.FK_IDRicovero
AND Intervento.IDIntervento = InterventiPerRicoveri.FK_IDIntervento
AND Intervento.Costo > 2000.00
2. Fornire l’elenco delle strutture ospedaliere private in ordine di provincia di appartenenza e, a parità di provincia, in ordine alfabetico di denominazione
SELECT *
FROM `Struttura`
WHERE Struttura.Tipo = 'Privato'
ORDER BY Struttura.Provincia, Struttura.Nome;
3. Visualizzare un elenco delle unità operative per cui risultino più di 100 ricoveri
SELECT UnitaOperativa.IDUnita
FROM UnitaOperativa, Ricovero
WHERE UnitaOperativa.IDUnita = Ricovero.FK_IDUnita
GROUP BY UnitaOperativa.IDUnita
HAVING COUNT(Ricovero.IDRicovero) > 100;
4. Fornire il numero di pazienti ricoverati causa COVID a partire da marzo 2020
SELECT COUNT(Ricovero.IDRicovero)
FROM Ricovero
WHERE Ricovero.Causa = 'covid'
AND Ricovero.DataRicovero > 2020-03-01
Pagina Web
Realizziamo una pagina di esempio che mostra le informazioni delle strutture appartenenti ad una determinata AUSL selezionabile mediante tendina. L’accesso alla pagina descritta, viene consentito solo dietro un accesso con form di login. Qui per semplicità la username pippo e password pippo sono cablate staticamente senza l’uso di funzioni di hash e db. Uno spunto per elaborare l’uso delle sessioni. La stessa tendina della pagina principale, la realizziamo scegliendo le voci attraverso opportuna query. Scegliamo come linguaggio il PHP ampiamente sviluppato in classe e mediamente in molte scuole. L’interfaccia grafica viene lasciata minimale nell’aspetto per ricalcare la realizzazione realistica del codice su carta nella prova.
Le immagini che descrivono il codice seguente. L’alunno ovviamente su foglio può limitarsi ad una idea di disegno stilizzato di come vorrebbe venisse a schermo la pagina.


<?php
session_start();
?>
<!DOCTYPE html>
<html>
<head>
<title>Gestione AUSL</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/stile.css" rel="stylesheet" type="text/css">
</head>
<body>
<main>
<form method="post" action="index.php">
<h1>Login</h1>
<input type="text" id="username" placeholder="Username" name="username"><br><br>
<input type="password" id="password" placeholder="Password" name="password"><br><br>
<button type="submit" name="login">Accedi</button>
</form>
<?php
if (isset($_SESSION['session_id']))
{
header('Location: ausl.php');
exit;
}
if (isset($_POST['login']))
{
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($username) || empty($password))
{
$msg = 'Inserisci username e password %s';
}
else
{
if ($username != "pippo" || $password != "pippo")
{
$msg = 'Credenziali utente errate';
}
else
{
session_regenerate_id();
$_SESSION['session_id'] = session_id();
$_SESSION['session_user'] = "pippo";
header('Location: ausl.php');
exit;
}
}
printf($msg, '<a href="index.php">torna indietro</a>');
}
?>
</main>
</body>
</html>
La pagina principale ha un codice un po’ più complesso. Abbiamo deciso di usare AJAX per reperire le informazioni du database, trasportarle in JSON sulla pagina che le renderizza con un piccolo ciclo JavaScript. Barra di navigazione, footer sono elementi incorporati, così come la configurazione del database, tutto con include e require.
<!DOCTYPE html>
<html lang="it">
<head>
<title>AUSL 2.0</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/stile.css" rel="stylesheet" type="text/css">
</head>
<body>
<?php include "header.php" ?>
<?php include "nav.php" ?>
<main>
<h2>Situazione AUSL</h2>
<?php
require_once("db.config.php");
$connessione = mysqli_connect($mysql_host,$mysql_user,$mysql_pass,$mysql_db);
if (mysqli_connect_errno()) die("Connessione non riuscita: " . mysqli_error($connessione));
$query = "SELECT * FROM AUSL AS A";
$res = mysqli_query($connessione,$query) or die("Errore nella login: " . mysqli_error($connessione));
$i = 0;
echo "<label for=\"select-ausl\">Scegli una AUSL: </label>";
echo "<select name=\"ausl\" id=\"select-ausl\">";
while ($row = mysqli_fetch_assoc($res))
{
$nome = $row['NomeAUSL'];
$descrizione = $row['Descrizione'];
if ($i == 0)
{
echo "<option value=\"\"> </option>";
}
$i++;
echo "<option value=\"$nome\">$nome</option>";
}
echo "</select>";
mysqli_close($connessione);
?>
<table id="tabella-strutture" border=1>
<thead>
<th>Codice</th>
<th>Nome</th>
<th>Indirizzo</th>
<th>Città</th>
<th>Provincia</th>
<th>Tipo</th>
</thead>
<tbody>
</tbody>
</table>
<script>
let selezione = document.querySelector("#select-ausl");
selezione.addEventListener("change", chiamaAjax);
function chiamaAjax()
{
var richiesta = new XMLHttpRequest();
richiesta.open("GET", "strutture.php?ausl="+selezione.value, true);
richiesta.setRequestHeader('Accept', 'application/json');
//console.log(" *** DEBUG *** ");
richiesta.onreadystatechange =
function ()
{
if(this.readyState === 4 && this.status === 200)
{
//costruisco la tabella
let selezione = document.querySelector("#tabella-strutture");
const res = JSON.parse(this.responseText);
//console.log(res);
for (var campo in res)
{
//console.log(campo);
//console.log(res[campo].IDStruttura);
let tr= document.createElement("tr");
let td1 = document.createElement('td');
let td2 = document.createElement('td');
let td3 = document.createElement('td');
let td4 = document.createElement('td');
let td5 = document.createElement('td');
let td6 = document.createElement('td');
let contenutotd1=document.createTextNode(res[campo].IDStruttura);
let contenutotd2=document.createTextNode(res[campo].Nome);
let contenutotd3=document.createTextNode(res[campo].Indirizzo);
let contenutotd4=document.createTextNode(res[campo].Città);
let contenutotd5=document.createTextNode(res[campo].Provincia);
let contenutotd6=document.createTextNode(res[campo].Tipo);
td1.appendChild(contenutotd1);
td2.appendChild(contenutotd2);
td3.appendChild(contenutotd3);
td4.appendChild(contenutotd4);
td5.appendChild(contenutotd5);
td6.appendChild(contenutotd6);
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tr.appendChild(td5);
tr.appendChild(td6);
selezione.appendChild(tr);
}
}
};
richiesta.send();
}
//prendo la selezione della tendina e scateno AJAX
</script>
</main>
<?php include "footer.php" ?>
</body>
</html>
<?php
header("Content-type: application/json");
require_once("db.config.php");
if (isset($_GET['ausl']))
{
$ausl = $_GET['ausl'];
}
$connessione = mysqli_connect($mysql_host,$mysql_user,$mysql_pass,$mysql_db);
if (mysqli_connect_errno()) die("Connessione non riuscita: " . mysqli_error($connessione));
$query = "SELECT * FROM Struttura AS S WHERE S.FK_NomeAusl = \"$ausl\"";
$res = mysqli_query($connessione,$query) or die("Errore nella login: " . mysqli_error($connessione));
$jsonarray= array();
while ($row = mysqli_fetch_assoc($res))
{
$jsonarray[] = $row;
}
mysqli_close($connessione);
echo json_encode($jsonarray);
exit;
?>
<?php
//da personalizzare con le credenziali del vostro dabase
$mysql_host = "localhost";
$mysql_user = "root";
$mysql_pass = "";
$mysql_db = "AUSL";
?>
<header>
<div id="logo"><img src="img/logo.png" alt="logo"></div>
<div id="title">Gestione AUSL 2.0</div>
</header>
<nav>
<a href="ausl.php">Home</a>
<a href="paziente.php">Pazienti</a>
<a href="intervento.php">Interventi</a>
<a href="ricovero.php">Ricoveri</a>
<a href="struttura.php">Strutture</a>
</nav>
<footer>Realizzato da Alfredo Centinaro</footer>
Quesito 1
Quesito 2
Quesito 3
Quesito 4
Ultima modifica 7 Aprile 2023