pubblicato il 31/05/2015

POTENZIAMENTO - PARTE A


Scaricare il seguente file ZIP contenente le tabelle necessarie per l'esercitazione. La struttura del DB è la seguente:

dove:
- La tabella studenti contiene i dati anagrafici dello studente. Il campo booleano Ripetente contiene True se lo studente è stato bocciato l'anno precedente mentre il campo booleano Bocciato contiene true se è stato bocciato l'anno corrente (sarà compilato a fine anno!).
- La tabella assenze contiene le assenze degli studenti. Attenzione: il campo DataAssenza è testuale. Il campo AssenzaTattica è booleano ed indica se la data dell'assenza coincide con una verifica. Il campo Ore ammette come possibili valori: 1 (assenza durante tutta l'ora di lezione) R (ritardo) G (assenza giustificata per altre attività scolastiche autorizzate) A (uscita prima della fine dell'ora)
- La tabella verifiche contiene i voti delle verifiche. Attenzione il campo DataVerifica è testuale. Il campo modulo è il numero identificativo dell'argomento (1 per il primo modulo, 2 per il secondon modulo etc.). Il voto (che è un campo testuale!) assume i seguenti valori: intero da 1.. 10 (se è una valutazione effettiva) + (bonus) - (penalty) * (controllo esercitazione) M (nota di merito) V (richiamo verbale) S (ammonizione scritta: nota sul registro). Il votoIn100esimi è un campo numerico di tipo double che contiene la reale valutazione numerica con 2 cifre decimali della prova.
- La tabella colloqui contiene le registrazioni dei colloqui. Il campo DataColloquio è di tipo data/ora. Il campo HaPrenotato è booleano ed è impostato a true se lo studente ha effettuato la prenotazione tramite web. Il campo QualeGenitore contiene il genitore che è venuto a colloquio ("Mamma", "Papà", "Entrambe", "Altro: ...")
Si noti che all'interno del file di Access sono state definite le seguenti funzioni:

Function Annata(Classe As String) As String
Dim a As Byte
   If IsNumeric((Left(Classe, 1))) Then
      If (Left(Classe, 1) = "1") Then
         Annata = "prima"
      ElseIf (Left(Classe, 1) = "2") Then
         Annata = "seconda"
      ElseIf (Left(Classe, 1) = "3") Then
         Annata = "terza"
      ElseIf (Left(Classe, 1) = "4") Then
         Annata = "quarta"
      ElseIf (Left(Classe, 1) = "5") Then
         Annata = "quinta"
      Else
         Annata = "????"
      End If
   Else
      Annata = "????"
   End If
End Function

Function My_PrimaLetteraMaiuscola(s As String) As String
   My_PrimaLetteraMaiuscola = UCase(Left(s, 1)) & LCase(Mid(s, 2))
End Function

Function Tassonomia(Voto, Optional Cosa As String = "Testo") As String
Dim v As Double
Dim TestoTassonomia As String
Dim OrdineTassonomia As String

   If IsNumeric(Voto) Then
      v = CDbl(Voto)
      If (v >= 0 And v <= 2.5) Then
         TestoTassonomia = "Estremamente Insufficiente"
         OrdineTassonomia = "A"
      ElseIf (v > 2.5 And v <= 4.5) Then
         TestoTassonomia = "Gravemente Insufficiente"
         OrdineTassonomia = "B"
      ElseIf (v > 4.5 And v < 5.5) Then
         TestoTassonomia = "Insufficiente"
         OrdineTassonomia = "C"
      ElseIf (v > 5.5 And v < 6.5) Then
         TestoTassonomia = "Sufficiente"
         OrdineTassonomia = "D"
      ElseIf (v > 6.5 And v < 7.5) Then
         TestoTassonomia = "Discreto"
         OrdineTassonomia = "E"
      ElseIf (v > 7.5 And v < 8.5) Then
         TestoTassonomia = "Buono"
         OrdineTassonomia = "F"
      ElseIf (v > 8.5 And v <= 10) Then
         TestoTassonomia = "Eccellente"
         OrdineTassonomia = "G"
      Else
         TestoTassonomia = "NC"
         OrdineTassonomia = "Z"
      End If
   Else
      TestoTassonomia = "NC"
      OrdineTassonomia = "Z"
   End If
   If (Cosa = "Testo") Then
      Tassonomia = TestoTassonomia
   Else
      Tassonomia = OrdineTassonomia
   End If
End Function

Attenzione: il file di access contiene già le funzioni qui elencate per cui non è necessario ricrearle

MYSQL: Stored Procedure equivalenti

-- -----------------------------------------------------
-- CREAZIONE FUNZIONI
-- -----------------------------------------------------
DROP FUNCTION IF EXISTS  MeseInItaliano;
DELIMITER //
CREATE FUNCTION MeseInItaliano(Giorno DATE) RETURNS VARCHAR(15)
BEGIN
	DECLARE NomeMese VARCHAR(15);
	DECLARE mese INT;
	SET mese=MONTH(Giorno);
	if (mese=1) THEN 
		SET NomeMese='Gennaio';
	elseif (mese=2) THEN 
		SET NomeMese='Febbraio';
	elseif (mese=3) THEN 
		SET NomeMese='Marzo';
	elseif (mese=4) THEN 
		SET NomeMese='Aprile';
	elseif (mese=5) THEN 
		SET NomeMese='Maggio';
	elseif (mese=6) THEN 
		SET NomeMese='Giugno';
	elseif (mese=7) THEN 
		SET NomeMese='Luglio';
	elseif (mese=8) THEN 
		SET NomeMese='Agosto';
	elseif (mese=9) THEN 
		SET NomeMese='Settembre';
	elseif (mese=10) THEN 
		SET NomeMese='Ottobre';
	elseif (mese=11) THEN 
		SET NomeMese='Novembre';
	elseif (mese=12) THEN 
		SET NomeMese='Dicembre';
	end if;
	RETURN NomeMese;
END //
DELIMITER ;

DROP FUNCTION IF EXISTS  GiornoInItaliano;
DELIMITER //
CREATE FUNCTION GiornoInItaliano(Giorno DATE) RETURNS VARCHAR(15)
BEGIN
	DECLARE NomeGiorno VARCHAR(15);
	DECLARE GiornoW INT;
	SET GiornoW=WEEKDAY(Giorno);
	if (GiornoW=0) THEN 
		SET NomeGiorno='Lunedì';
	elseif (GiornoW=1) THEN 
		SET NomeGiorno='Martedì';
	elseif (GiornoW=2) THEN 
		SET NomeGiorno='Mercoledì';
	elseif (GiornoW=3) THEN 
		SET NomeGiorno='Giovedì';
	elseif (GiornoW=4) THEN 
		SET NomeGiorno='Venerdì';
	elseif (GiornoW=5) THEN 
		SET NomeGiorno='Sabato';
	elseif (GiornoW=6) THEN 
		SET NomeGiorno='Domenica';
	end if;
	RETURN NomeGiorno;
END //
DELIMITER ;

DROP FUNCTION IF EXISTS  IsNumeric;
CREATE FUNCTION IsNumeric (sIn varchar(1024)) RETURNS tinyint
RETURN sIn REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';

DROP FUNCTION IF EXISTS  My_PrimaLetteraMaiuscola;
CREATE FUNCTION My_PrimaLetteraMaiuscola (s varchar(1024)) RETURNS varchar(1024)
RETURN CONCAT(UCASE(LEFT(s,1)),LCASE(MID(s,2)));

DROP FUNCTION IF EXISTS  Annata;
DELIMITER //
CREATE FUNCTION Annata(Classe VARCHAR(25)) RETURNS VARCHAR(10)
BEGIN
	DECLARE Anno CHAR(1);
	DECLARE frase VARCHAR(10);
	SET Anno=LEFT(Classe,1);
	IF (IsNumeric(Anno)) THEN
		IF (Anno="1") THEN
			SET frase = "prima";
 		ELSEIF (Anno="2") THEN
			SET frase = "seconda";
		ELSEIF (Anno="3") THEN
			SET frase = "terza";
		ELSEIF (Anno="4") THEN
			SET frase = "quarta";
		ELSEIF (Anno="5") THEN
			SET frase = "quinta";
		ELSE
			SET frase = "?????";
		END IF;
	ELSE
		SET frase = "?????";
	END IF;
	RETURN frase;
END //
DELIMITER ;

DROP FUNCTION IF EXISTS  Tassonomia;
DELIMITER //
CREATE FUNCTION Tassonomia(Voto FLOAT, Cosa TEXT) RETURNS VARCHAR(50)
BEGIN
	DECLARE Tassonomia VARCHAR(50);
	DECLARE TestoTassonomia VARCHAR(50);
	DECLARE OrdineTassonomia CHAR(1);
	DECLARE v INT;
	IF (IsNumeric(Voto)) THEN
		SET v=CAST(Voto AS UNSIGNED);
		If (v>=0 And v<=2.5 ) THEN
			SET TestoTassonomia = "Estremamente Insufficiente";
			SET OrdineTassonomia = "A";
		ELSEIF (v > 2.5 And v <= 4.5) THEN
			SET TestoTassonomia = "Gravemente Insufficiente";
			SET OrdineTassonomia = "B";
		ELSEIF (v > 4.5 And v < 5.5) THEN
			SET TestoTassonomia = "Insufficiente";
			SET OrdineTassonomia = "C";
		ELSEIF (v > 5.5 And v < 6.5) THEN
			SET TestoTassonomia = "Sufficiente";
			SET OrdineTassonomia = "D";
 		ELSEIF (v > 6.5 And v < 7.5) THEN
			SET TestoTassonomia = "Discreto";
			SET OrdineTassonomia = "E";
 		ELSEIF (v > 7.5 And v < 8.5) THEN
 			SET TestoTassonomia = "Buono";
			SET OrdineTassonomia = "F";
		ELSEIF (v > 8.5 And v <= 10) THEN
 			SET TestoTassonomia = "Eccellente";
			SET OrdineTassonomia = "G";
		ELSE
 			SET TestoTassonomia = "NC";
			SET OrdineTassonomia = "Z";
 		END IF;
	ELSE
		SET TestoTassonomia = "NC";
		SET OrdineTassonomia = "Z";
	END IF;
	IF (Cosa = "Testo") THEN
		SET Tassonomia = TestoTassonomia;
    ELSE
		SET Tassonomia = OrdineTassonomia;
	END IF;
	RETURN Tassonomia;
END //
DELIMITER ;

ESERCIZIO 1 - IV-M2.5A.1

INTERPRETA CORRETTAMENTE I SEGUENTI COMANDI SQL SEMPLICI (in blu con ACCESS - in verde in MySQL):

as1)
SELECT Cognome, Nome FROM Studenti
WHERE (Classe like "3*") AND (Sesso="F")

MYSQL:

SELECT Cognome, Nome FROM Studenti
WHERE (Classe like "3%") AND (Sesso="F");

as2)
SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE DataVerifica Like "*/02/2014"

MYSQL:

SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE DataVerifica Like "%/02/2014";

as3)
SELECT * FROM Classi WHERE [Vuoi visualizzare tutte le classi in elenco ?]='Si'

MYSQL: Nell'interfaccia testuale non è possibile valorizzare, durante l'esecuzione del comando SQL, una variabile pertanto la devo impostare manualmente nello script con il comando SET

SET @`Vuoi visualizzare tutte le classi in elenco ?`='Si';
SELECT * FROM Classi WHERE @`Vuoi visualizzare tutte le classi in elenco ?` = 'Si';

Oppure posso ricorrere ad una stored procedure a cui passo il parametro richiesto

DROP PROCEDURE IF EXISTS Vuoi_visualizzare_tutte_le_classi_in_elenco;
DELIMITER //
CREATE PROCEDURE Vuoi_visualizzare_tutte_le_classi_in_elenco(risposta VARCHAR(50))
BEGIN
   SELECT * FROM Classi WHERE risposta = 'Si';
END //
DELIMITER ;
CALL Vuoi_visualizzare_tutte_le_classi_in_elenco('Si');
CALL Vuoi_visualizzare_tutte_le_classi_in_elenco('No');

as4)
SELECT Cognome & " " & Studenti.Nome AS Nominativo FROM Studenti
WHERE Ripetente AND Bocciato

MYSQL:

SELECT CONCAT(Cognome," ",Studenti.Nome) AS Nominativo FROM Studenti
WHERE Ripetente AND Bocciato;

as5)
SELECT Cognome FROM Studenti
WHERE (Cognome Like "*U*") And ( (Cognome Like "D*") And (Cognome Like "*I") );

MYSQL:

SELECT Cognome FROM Studenti
WHERE (Cognome Like "%U%") And ( (Cognome Like "D%") And (Cognome Like "%I") );

as6)
SELECT Cognome, Nome, [Di quale classe ?] AS Classe, #03/01/2015# as [Stampato Il]
FROM Studenti WHERE [Di quale classe ?]=Classe

MYSQL: utilizzo una stored procedure a cui passo come parametro la classe

DROP PROCEDURE IF EXISTS Di_Quale_Classe;
DELIMITER //
CREATE PROCEDURE Di_Quale_Classe(vClasse VARCHAR(50))
BEGIN
   SELECT Cognome, Nome, vClasse AS Classe,
   STR_TO_DATE('03/01/2015','%m/%d/%Y') AS `Stampato Il`
   FROM Studenti WHERE Classe= vClasse;
END //
DELIMITER ;
CALL Di_Quale_Classe('3O');

as7)
SELECT DISTINCT DataColloquio AS [Colloqui Generali] FROM Colloqui
WHERE (tipologia="Quadrimestrale")
AND (DataColloquio>=#1/31/2014#) AND (DataColloquio<=#06/08/2014#);

MYSQL:

SELECT DISTINCT DATE_FORMAT(DataColloquio,'%d/%m/%Y') AS 'Colloqui Generali' FROM Colloqui
WHERE (Tipologia='Quadrimestrale')
AND ( DataColloquio>='2014-01-31' AND DataColloquio<='2014-06-08' );

as8)
SELECT Classe, Cognome & " " & Nome As Nominativo, [Che giorno è oggi ?] AS [Stampato Il]
FROM Studenti ORDER BY Classe, Cognome, Nome;

MYSQL: Valorizzo una variabile con la data del giorno che desidero compaia in visualizzazione

SET @`Che giorno è oggi ?`='11/05/2015';
SELECT Classe, CONCAT(Cognome," ",Nome) As Nominativo, @`Che giorno è oggi ?` AS `Stampato Il`
FROM Studenti ORDER BY Classe, Cognome, Nome;

as9)
SELECT Cognome, Nome, NrAccessiRegistro FROM Studenti
WHERE (NrAccessiRegistro>20) AND (Bocciato OR Ripetente);

MYSQL:

SELECT Cognome, Nome, NrAccessiRegistro FROM Studenti
WHERE (NrAccessiRegistro>20) AND (Bocciato OR Ripetente);

as10)
SELECT Studenti.Cognome, Studenti.Nome, Studenti.UltimoAccessoAlForum, Studenti.UltimoAccessoRegistro
FROM Studenti
Where ( (Studenti.UltimoAccessoAlForum - Studenti.UltimoAccessoRegistro)<=1
and (Studenti.UltimoAccessoAlForum - Studenti.UltimoAccessoRegistro)>=-1)

MYSQL:

SELECT Studenti.Cognome, Studenti.Nome, Studenti.UltimoAccessoAlForum, Studenti.UltimoAccessoRegistro
FROM Studenti
WHERE ( TIMESTAMPDIFF(SECOND,Studenti.UltimoAccessoAlForum, UltimoAccessoRegistro)<=24*60*60
AND (TIMESTAMPDIFF(SECOND,UltimoAccessoAlForum,UltimoAccessoRegistro))>=-24*60*60);

ESERCIZIO 2 - IV-M2.5A.2

INTERPRETARE CORRETTAMENTE I SEGUENTI COMANDI SQL SEMPLICI CONTENENTI ISTRUZIONI VBA:

bs1)
SELECT Cognome, Nome FROM Studenti
WHERE (Left(Classe,1)>="3") AND (Sesso="F")

MYSQL:

SELECT Cognome, Nome FROM Studenti
WHERE (Left(Classe,1)>="3") AND (Sesso="F");

bs2)
SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE (Format(CDate(DataVerifica),"mmyyyy")="022014")
ORDER BY CDate(DataVerifica)

MYSQL:

SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE (DATE_FORMAT(STR_TO_DATE(DataVerifica,'%d/%m/%Y'),"%m%Y")="022014")
ORDER BY STR_TO_DATE(DataVerifica,'%d/%m/%Y');

bs3)
SELECT TOP 1 CDate(DataVerifica) AS Giorno FROM Verifiche
WHERE (Tipologia="Orale") AND (CByte(Voto)>5)
ORDER BY CDate(DataVerifica)

MYSQL:

SELECT DataVerifica AS Giorno FROM Verifiche
WHERE (Tipologia="Orale") AND (CONVERT(Voto,UNSIGNED)>5)
ORDER BY STR_TO_DATE(DataVerifica,'%d/%m/%Y') LIMIT 1;

bs4)
SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE Year(CDate(DataVerifica))=2014 AND month(Cdate(DataVerifica))=2
ORDER BY CDate(DataVerifica);

MYSQL:

SELECT DataVerifica, Tipologia, Voto FROM Verifiche
WHERE YEAR(STR_TO_DATE(DataVerifica,'%d/%m/%Y'))=2014
AND MONTH(STR_TO_DATE(DataVerifica,'%d/%m/%Y'))=2
ORDER BY STR_TO_DATE(DataVerifica,'%d/%m/%Y');

bs5)
SELECT Cognome FROM Studenti
WHERE Instr(Cognome,"U")>0 And ( Left(Cognome,1)="D" And Right(Cognome,1)="I" )

MYSQL:

SELECT Cognome FROM Studenti
WHERE Instr(Cognome,"U")>0 And ( Left(Cognome,1)="D" And Right(Cognome,1)="I" );

bs6)
SELECT Cognome, Nome, [Di quale classe ?] AS Classe, Now() AS [Stampato Il]
FROM Studenti WHERE [Di quale classe ?]=Classe;

MYSQL: Utilizzando una variabile valorizzata con il nome della classe da visualizzare possiamo fornire la seguente soluzione:

SET @`Di quale classe ?`='3O';
SELECT Cognome, Nome, @`Di quale classe ?` AS Classe
FROM Studenti WHERE Classe=@`Di quale classe ?`;

Se il character set e la collation della tabella/campo risultano incompatibili con quelli impostati per la connessione (definiti nelle variabili: character_set_connection e collation_connection) possiamo avere il seguente errore:

infatti con il seguente comando posso verificare che il campo Classe e la variabile @`Di quale classe ?` hanno charset e collation differenti:

SET @`Di quale classe ?`='3O';
SELECT  CharSet(Classe), Collation(Classe),  CharSet(@`Di quale classe ?`), Collation(@`Di quale classe ?`)
FROM Studenti LIMIT 1;

pertanto la query va riscritta nel seguente modo:

SET character_set_connection='latin1';
SET @`Di quale classe ?`='4T';
SELECT Cognome, Nome, Classe, DATE_FORMAT('2015-03-01','%m/%d/%Y') as `Stampato Il`
FROM Studenti WHERE Classe=@`Di quale classe ?`;
 

oppure:

SET @`Di quale classe ?`='4T';
SELECT Cognome, Nome, Classe, DATE_FORMAT('2015-03-01','%m/%d/%Y') as `Stampato Il`
FROM Studenti WHERE Classe=CONVERT(@`Di quale classe ?` USING latin1) COLLATE latin1_swedish_ci;
 

l'ultimo COLLATE è superfluo poichè latin1_swedish_ci è il default per il charset latin1 come si può verificare digitando il comando:

SHOW CHARACTER SET like 'latin1';

oppure:

SHOW CHARACTER SET WHERE CHARSET = 'latin1';

Approfondimento: I character set (insiemi di caratteri) sono tabelle che abbinano ai simboli visualizzabili su un computer un corrispondente valore binario. In ogni set di caratteri, una sequenza binaria corrisponde ad un carattere ben preciso. Di conseguenza, quando una stringa viene memorizzata utilizzando un certo set di caratteri, dovrà essere visualizzata attraverso quello stesso insieme, altrimenti alcuni caratteri potrebbero apparire diversi da come ce li aspettiamo. L’esempio classico di questo inconveniente si verifica in genere con le lettere accentate.

SELECT 'Latin1' AS `Set Caratteri`, CONVERT('àìòùè áíóúé' USING latin1) AS Testo;
SELECT 'binary ' AS `Set Caratteri`, CONVERT('àìòùè áíóúé' USING binary ) AS Testo;

MySQL, a partire dalla versione 4.1, ha introdotto un supporto molto avanzato alla gestione dei character set. Infatti ci consente di gestire i set di caratteri a livello di:
- server,
- database,
- tabella
- singola colonna
- client e di connessione.

Ad ogni set di caratteri sono associate una o più "collation", che rappresentano i modi possibili di confrontare le stringhe di caratteri facenti parte di quel character set. Questo termine potrebbe essere tradotto con l’italiano con "collazione" (termine arcaico ormai in disuso sinonimo di "confronto").

Quindi una tabella che utilizza character set "latin1" (quello maggiormente usato in Europa Occidentale) e collation "latin1_general_cs" avrà:
- un metodo di confronto non specifico per una determinata lingua (adatto quindi a + idiomi)
- “case sensitive” come indica la sigla “cs” finale, cioè tiene conto della differenza fra maiuscole e minuscole nell’ordinare o confrontare le stringhe.
Normalmente l’esistenza di una collation dedicata ad una singola lingua si ha quando le regole generali del set di caratteri non soddisfano le esigenze di quella lingua.

In generale il nome di ogni collation segue un determinato standard:
- inizia con il nome del character set a cui si riferisce,
- comprende di solito una specifica relativa alla lingua,
- termina con cs (case sensitive) o ci (case insensitive) oppure con bin quando il valore binario dei caratteri è utilizzato direttamente per i confronti.

Quindi avremo ad esempio:
latin1_swedish_ci per la collation svedese case insensitive di latin1,
latin1_german2_ci
per la collation, sempre case insensitive, basata sulle regole tedesche DIN-2,
utf8_bin per la collation binaria della codifica utf8 (Unicode). 

 Ogni collation è legata a un solo set di caratteri! Le istruzioni SQL seguenti:

SHOW CHARACTER SET;
SHOW COLLATION;

 ci consentono di ottenere rispettivamente:
- la lista dei set di caratteri (con la collation di default)
- la lista delle collation con il set di caratteri associato
disponibili sul server.

Come detto, MySQL gestisce character set e collation a diversi livelli: server, database, tabella, colonna. Parlando di dati, ovviamente ciò che è rilevante è quale character set viene utilizzato su ogni campo della singola tabellla di tipo CHAR, VARCHAR o TEXT. Tutti i charset definiti nei livelli superiori (server, database, tabella) hanno il solo scopo di definire il valore di default per il rispettivo livello inferiore.

I set di caratteri gestiti a livello di server, database, tabella, singola colonna (o campo), client e di connessione sono visualizzabili con il seguente comando:

SHOW VARIABLES LIKE 'character\_set\_%';

Possiamo impostare il character set nelle variabili character_set_client, character_set_results e character_set_connection utilizzando questo singolo comando:

SET NAMES 'nome charset';

per cui equivale a:

SET character_set_client = 'nome charset';
SET character_set_results = 'nome charset';
SET character_set_connection = 'nome charset';

In alternativa si poteva utilizzare anche il comando SQL:

SET CHARACTER SET 'nome charset';

che però è equivalente alla seguente sequenza di comandi:

SET character_set_client = 'nome charset';
SET character_set_results = 'nome charset';
SET collation_connection = @@collation_database;

Quando un client si connette ad un server MySQL spedisce il nome del set di caratteri che intende utilizzare. Il server imposta automaticamente le variabili character_set_client, character_set_results e character_set_connection a quel set di caratteri (esegue sostanzialmente un SET NAMES su quel set di caratteri). Quando un client richiede l'esecuzione di un comando SQL, come SELECT Colonna1 FROM Tabella, il server restituisce i valori contenuti nel campo Colonna1 utilizzando il set di caratteri che il client ha specificato quando si è connesso. La conversione potrebbe determinare delle perdite se ci sono caratteri non definiti nei charset coinvolti.

Le variabili di sistema character_set_client e character_set_results rappresentano, rispettivamente, il charset delle istruzioni in arrivo dal client e quello che sarà utilizzato per spedire le risposte.

Il comando SQL successivo mostra invece come la variabile character_set_database acquisisca in automantico il character set del db in uso

-- Creo un DB impostando un character set opportuno
CREATE DATABASE db1_buttare CHARACTER SET ucs2;
-- Visualizzo le variabili relative al charset
SHOW VARIABLES LIKE 'character\_set\_%';
USE DB1_Buttare; -- Cambio DB di default
-- Verifico che la character_set_database e' cambiata
SHOW VARIABLES LIKE 'character\_set\_%';
DROP DATABASE DB1_Buttare;

Il comando SQL successivo mostra quale charset venga utilizzato come default a livello di db, tabella e colonna:

-- Imposto i charset opportunamente per riconoscere quele sia il default utilizzato
SET character_set_server = 'dec8';
SET character_set_database = 'hp8';
SHOW VARIABLES LIKE 'character\_set\_%';
-- Creo un DB e al suo interno una tabella. Evito di usare USE DB1_buttare
CREATE DATABASE DB1_buttare;
CREATE TABLE DB1_buttare.Tabella1 (Campo1 VARCHAR(10));
-- Visualizzazione dei charset e dei collation applicati a livello di db, tabella e campo
SELECT "Default DB" AS Ambito, default_character_set_name AS CharSET, Default_Collation_Name AS Collation
       FROM information_schema.Schemata WHERE Schema_Name = "DB1_buttare"
UNION ALL
SELECT "Default TABELLA", CharSetAbbinato.character_set_name, Tabelle.Table_Collation
       FROM information_schema.tables Tabelle, information_schema.collation_character_set_applicability CharSetAbbinato
       WHERE CharSetAbbinato.collation_name = Tabelle.table_collation
       AND Tabelle.table_schema = "DB1_buttare" AND Tabelle.table_name = "Tabella1"
UNION ALL
SELECT "Default CAMPO", Character_Set_Name, Collation_Name
       FROM information_schema.columns
       WHERE Table_Schema = "DB1_buttare" AND Table_Name = "Tabella1" AND Column_Name = "Campo1";
-- Visualizzo le variabili di sistema per vedere se sono cambiate
SHOW VARIABLES LIKE 'character\_set\_%';
-- Eliminazione del db di prova
DROP DATABASE DB1_buttare;

Dall'output noto che il charset di default utilizzato è quello indicato nella variabile character_set_server.

Non indicare il character set o la collation durante la creazione di un DB comporta quindi l'utilizzo delle impostazioni a livello di server (variabile character_set_server ). Non indicare il character set o la collation durante la creazione di una tabella comporta l'utilizzo delle impostazioni del DB contenitore mentre non indicare il character set o la collation durante la creazione di un campo comporta l'utilizzo delle impostazioni della tabella associata. Lo si può verificare guardando i 2 successivi esempi.

Nel primo esempio si nota che quando creo un DB senza indicare ne charset ne collation allora le impostazioni nelle variabili character_set_server e collation_server vengano utilizzate per stabilire il collation e il charset da applicare (come del resto già precisato precedentemente). Qualora nella creazione del DB venga definito il charset allora la collation utilizzata è quella predefinita per quel charset (i default sono visibili con il comando: SHOW COLLATION WHERE `Default` = 'Yes';). Analogamente se creo una tabella senza indicare il charset all'interno di un db questa eredita il il charset e la collation del db contenitore. Lo stesso vale per il campo: se definisco un campo all'interno di una tabella questa assume il charset e la collation della tabella stesssa.

-- Controllo il collation predefinito per ucs2 ed imposto il charset e il collation di default
SET character_set_server = 'ucs2';
SET collation_server='ucs2_icelandic_ci';
-- Creazione del primo DB senza charset
CREATE DATABASE DB_UsaDefault;
CREATE TABLE DB_UsaDefault.Tabella_UsaDefault (
    Campo_UsaDefault VARCHAR(10),
    Campo_UsaUCS2 VARCHAR(10) CHARACTER SET ucs2);
CREATE TABLE DB_UsaDefault.Tabella_UsaUCS2 (
    Campo_UsaDefault VARCHAR(10),
    Campo_UsaUCS2 VARCHAR(10) CHARACTER SET ucs2) CHARACTER SET ucs2;
-- Creazione del secondo DB con charset impostato
CREATE DATABASE DB_UsaUCS2 CHARACTER SET ucs2;
CREATE TABLE DB_UsaUCS2.Tabella_UsaDefault (
    Campo_UsaDefault VARCHAR(10),
    Campo_UsaUCS2 VARCHAR(10) CHARACTER SET ucs2);
CREATE TABLE DB_UsaUCS2.Tabella_UsaUCS2 (
    Campo_UsaDefault VARCHAR(10),
    Campo_UsaUCS2 VARCHAR(10) CHARACTER SET ucs2) CHARACTER SET ucs2;
-- Visualizzo il charset e il collation applicati
SHOW COLLATION LIKE 'ucs2\_general\_ci%';
SELECT * FROM (
    SELECT Concat("Charset: ",Schema_Name) AS Ambito,
           default_character_set_name AS CharSET,
           Default_Collation_Name AS Collation
           FROM information_schema.Schemata WHERE Schema_Name like "DB_Usa%"
       UNION ALL
    SELECT CONCAT("charset: ",Tabelle.table_schema,".", Tabelle.table_name),
           CharSetAbbinato.character_set_name, Tabelle.Table_Collation
           FROM information_schema.tables Tabelle,
                information_schema.collation_character_set_applicability CharSetAbbinato
           WHERE CharSetAbbinato.collation_name = Tabelle.table_collation
           AND Tabelle.table_schema like "DB_Usa%" AND Tabelle.table_name like "Tabella%"
       UNION ALL
    SELECT CONCAT("charset: ",Table_Schema, ".",Table_Name,".",Column_Name),
           Character_Set_Name, Collation_Name
           FROM information_schema.columns
           WHERE Table_Schema like "DB_Usa%" AND Table_Name like "Tabella%" AND Column_Name like "Campo%"
) Risultati ORDER BY Ambito;
-- Elimino i db di prova
DROP DATABASE DB_UsaDefault;
DROP DATABASE DB_UsaUCS2;

Osservando l'output della sequenza SQL osserviamo che la collation ucs2_icelandic_ci definita nella variabile collation_server è stata utilizzata solo quando:
- il db non ha indicazioni sul charset da utilizzare
- la tabella non ha indicazioni sul charset da utilizzare e neppure il db che la contiene (eredito le impostazioni del db contenitore)
- il campo non ha indicazioni sul charset da utilizzare e neppure il db ne la tabella dove è definito (eredito le impostazioni della tabella associata)

 Nel secondo esempio la sequenza dei comandi SQL mostra come personalizzare la collation a livello di db, tabella e colonna:

-- Creazione del db e delle tabelle con tute le combinazioni di COLLATE
CREATE DATABASE DB1_buttare CHARACTER SET ucs2 COLLATE ucs2_bin;
CREATE TABLE DB1_buttare.Tabella1_None (Campo1_None VARCHAR(10));
CREATE TABLE DB1_buttare.Tabella2_None (Campo1_CS_ucs2 VARCHAR(10) CHARACTER SET ucs2);
CREATE TABLE DB1_buttare.Tabella3_CS_ucs2 (Campo1_None VARCHAR(10)) CHARACTER SET ucs2;
CREATE TABLE DB1_buttare.Tabella4_CS_ucs2 (Campo1_CS_ucs2 VARCHAR(10) CHARACTER SET ucs2) CHARACTER SET ucs2;
CREATE TABLE DB1_buttare.Tabella5_CS_ucs2_CO_ucs2bin (Campo1_None VARCHAR(10)) CHARACTER SET ucs2 COLLATE ucs2_bin;
CREATE TABLE DB1_buttare.Tabella6_CS_ucs2_CO_ucs2bin (Campo1_CS_ucs2 VARCHAR(10) CHARACTER SET ucs2) CHARACTER SET ucs2 COLLATE ucs2_bin;
-- Mostro il collation predefinito di ucs2
SHOW COLLATION LIKE 'ucs2\_general\_ci%';
SELECT * FROM (
         SELECT Concat("Charset: DB") AS Ambito, default_character_set_name AS CharSET,
                Default_Collation_Name AS Collation
                FROM information_schema.Schemata WHERE Schema_Name like "DB_%"
     UNION ALL
         SELECT CONCAT("charset: DB.", Tabelle.table_name) AS Ambito,
                CharSetAbbinato.character_set_name, Tabelle.Table_Collation
                FROM information_schema.tables Tabelle,
                     information_schema.collation_character_set_applicability CharSetAbbinato
                WHERE CharSetAbbinato.collation_name = Tabelle.table_collation
                AND Tabelle.table_schema like "DB_%" AND Tabelle.table_name like "Tabella%"
     UNION ALL
         SELECT CONCAT("charset: DB.",Table_Name,".",Column_Name) AS Ambito, Character_Set_Name, Collation_Name
                FROM information_schema.columns
                WHERE Table_Schema like "DB_%" AND Table_Name like "Tabella%" AND Column_Name like "Campo%"
) risultati ORDER BY Ambito;
DROP DATABASE DB1_buttare;

Si osservi che la collation ucs2_bin, assegnata al DB, viene utilizzata tutte le volte in cui nel comando di creazione non viene citato uno specifico charset. Quando invece viene indicato il charset ucs2 allora la collation che viene utilizzata è ucs2_general_ci ovvero  quella predefinita per ucs2.

Per concludere un comando che mostra le collation utilizzate in caso di costanti, funzioni, campi ...

-- Imposto i charset opportunamente per riconoscerli
SET character_set_client ='dec8';
SET character_set_connection ='hp8';
SET character_set_results ='ascii';
SET character_set_database = 'latin1';
SET character_set_server = 'latin2';
-- Creo il DB ed una tabella con un record
CREATE DATABASE DB1_buttare CHARACTER SET latin1 COLLATE latin1_danish_ci ;
CREATE TABLE DB1_buttare.Tabella1 (Campo1 VARCHAR(10), CAMPO2 INT);
INSERT INTO DB1_buttare.Tabella1(Campo1,Campo2) VALUES ('Marco',1);
-- Mostro i collation utilizzati in diverse casistiche
SET @`Che nome hai ?`="Marco";
SET @`Quanti anni hai ?`=18;
SELECT 'Costante Testo' AS Tipo, COLLATION('Si') AS `Collate usato` UNION ALL
SELECT 'Costante Numero' AS Tipo, COLLATION(100) AS `Collate usato` UNION ALL
SELECT 'Variabile stringa', COLLATION(@`Che nome hai ?`) UNION ALL
SELECT 'Variabile numerica', COLLATION(@`Quanti anni hai ?`) UNION ALL
SELECT 'Variabile (non definita)', COLLATION(@VarNonDefinita) UNION ALL
-- LAST_INSERT_ID(), SCHEMA(), CONNECTION_ID(), USER() ...
SELECT 'Information Function()', COLLATION(VERSION()) UNION ALL
SELECT 'Funzione() Stringa', COLLATION(SPACE(3)) UNION ALL
SELECT 'Funzione() binaria', COLLATION(SYSDATE()) UNION ALL
(SELECT 'Campo Testuale', COLLATION(Campo1) FROM DB1_buttare.Tabella1 LIMIT 1) UNION ALL
(SELECT 'Campo Numerico', COLLATION(Campo2) FROM DB1_buttare.Tabella1 LIMIT 1);
show variables like 'character\_set\_%';
show variables like 'coll%';
DROP DATABASE DB1_buttare;

Si osservi che le variabili, le costanti e i campi non testuali vengono associate ad un collate binary. Le funzioni informative (BENCHMARK(), CHARSET(), COERCIBILITY(), COLLATION(), CONNECTION_ID(), CURRENT_USER(), DATABASE(), FOUND_ROWS(), LAST_INSERT_ID(), ROW_COUNT(), SCHEMA(), SESSION_USER(), SYSTEM_USER(), USER(), VERSION() ) restituiscono il charset e la collation del sistema (variabile: character_set_system). Costanti, variabili e funzioni testuali utilizzano il charset e la collation di connessione (variabile: character_set_connection e collate_connection).

Quindi character_set_connection e collation_connection  sono utilizzate dal server per convertire le istruzioni ricevute e fare confronti fra valori di tipo stringa.

bs7)
SELECT * FROM Classi
WHERE Indirizzo=IIf([Digita 1 per Classi Area Scientifica 2 Scienze Applicate ?]=1,"Scientifica","Scienze Applicate");

MYSQL: utilizzando una prepared statement:

PREPARE stmt FROM 'SELECT * FROM Classi WHERE Indirizzo=If(?=1,"Scientifica","Scienze Applicate")';
SET @`Digita 1 per Classi Area Scientifica 2 Scienze Applicate ?`=1;
EXECUTE stmt USING @`Digita 1 per Classi Area Scientifica 2 Scienze Applicate ?`;
SET @`Digita 1 per Classi Area Scientifica 2 Scienze Applicate ?`=2;
EXECUTE stmt USING @`Digita 1 per Classi Area Scientifica 2 Scienze Applicate ?`;
DEALLOCATE PREPARE stmt;

bs8)
SELECT Ucase(Left(Cognome,1)) & Lcase(mid(Cognome,2)) & " " & Ucase(Nome) AS Nominativo
FROM Studenti ORDER BY COGNOME, Nome;

MYSQL:

SELECT CONCAT(Ucase(Left(Cognome,1)),Lcase(mid(Cognome,2))," ",Ucase(Nome)) AS Nominativo
FROM Studenti ORDER BY COGNOME, Nome;

bs9)
SELECT Cognome & " " & Nome & " frequenta la classe " &
Annata(Classe)
& " sezione " & right(Classe,1) FROM Studenti
ORDER BY Cognome, Nome

MYSQL:

SELECT CONCAT(Cognome," ",Nome," frequenta la classe ",
CAST(Annata(Classe) AS CHAR CHARACTER SET UTF8)," sezione ",right(Classe,1)) FROM Studenti
ORDER BY Cognome, Nome;

bs10)
SELECT Cognome, Nome,
My_PrimaLetteraMaiuscola
(
    IIf(IsDate(ArrivatoIl),
        "è arrivato " & format(ArrivatoIl,"dddd, d mmmm yyyy"),
        ""
       ) &
    IIf(IsDate(RitiratoDal) and IsDate(ArrivatoIl)," e ","") &
    IIf(IsDate(RitiratoDal),
        "si è ritirato " & format(RitiratoDal,"dddd, d mmmm yyyy"),
        ""
        )
) AS [Ritirati o Iscritti dopo]
FROM Studenti
WHERE ( IsDate(RitiratoDal) OR IsDate(ArrivatoIl) )
ORDER BY IIf(IsDate(ArrivatoIl),ArrivatoIl,RitiratoDal);

MYSQL:

SELECT Cognome, Nome,
My_PrimaLetteraMaiuscola
(
   CONCAT(
      If(IsNull(ArrivatoIl),"",
         CONCAT("è arrivato ",DATE_format(ArrivatoIl,"%W, %e %M %Y"))),
      If(NOT(IsNull(RitiratoDal)) and NOT(IsNull(ArrivatoIl))," e ",""),
      If(IsNull(RitiratoDal),"",
         CONCAT("si è ritirato ",DATE_format(RitiratoDal,"%W, %e %M %Y")))
   )
) AS 'Ritirati o Iscritti dopo'
FROM Studenti
WHERE NOT ( IsNull(RitiratoDal) AND IsNull(ArrivatoIl) )
ORDER BY If(IsNull(ArrivatoIl),ArrivatoIl,RitiratoDal);

Per ottenere l'elenco con i nomi in italiano possiamo sfruttare le funzioni MeseInItaliano() e GiornoInItaliano() che sono state definite all'interno del nostro db DATISTUDENTE

SELECT Cognome, Nome,
My_PrimaLetteraMaiuscola
(
CONCAT(
        If(IsNull(ArrivatoIl),"",
           CONCAT("è arrivato ",
                  GiornoInItaliano(ArrivatoIl),DATE_format(ArrivatoIl," %e "),
                  MeseInItaliano(ArrivatoIl),DATE_format(ArrivatoIl," %Y"))),
        If(NOT(IsNull(RitiratoDal)) and NOT(IsNull(ArrivatoIl))," e ",""),
        If(IsNull(RitiratoDal),"",
           CONCAT("si è ritirato ",
                  GiornoInItaliano(RitiratoDal),DATE_format(RitiratoDal," %e "),
                  MeseInItaliano(RitiratoDal),DATE_format(RitiratoDal," %Y")))
      )
) AS 'Ritirati o Iscritti dopo'
FROM Studenti
WHERE NOT ( IsNull(RitiratoDal) AND IsNull(ArrivatoIl) )
ORDER BY If(IsNull(ArrivatoIl),ArrivatoIl,RitiratoDal);

ESERCIZIO 3 - IV-M2.5A.3

INTERPRETARE CORRETTAMENTE I SEGUENTI COMANDI SQL STATISTICI CON ISTRUZIONI VBA:

cs1)
SELECT Classe, Count(*) AS Nr FROM Studenti
GROUP BY Classe ORDER BY Classe

MYSQL:

SELECT Classe, Count(*) AS Nr FROM Studenti
GROUP BY Classe ORDER BY Classe;

cs2)
SELECT Format(DataColloquio,"mmmm yyyy") AS Mese, Count(*) AS Nr FROM Colloqui
GROUP BY Format(DataColloquio,"mmmm yyyy"), CLng(Format(DataColloquio,"yyyymm"))
ORDER BY CLng(Format(DataColloquio,"yyyymm"))

MYSQL:

SELECT DATE_Format(DataColloquio,"%M %Y") AS Mese, Count(*) AS Nr FROM Colloqui
GROUP BY DATE_Format(DataColloquio,"%Y%m"), DATE_Format(DataColloquio,"%M %Y")
ORDER BY DATE_Format(DataColloquio,"%Y%m");

Per ottenere l'elenco con i nomi dei mesi in italiano possiamo sfruttare la funzione MeseInItaliano() che è stata definita all'interno del nostro db DATISTUDENTI

SELECT CONCAT(MeseInItaliano(DataColloquio)," ",DATE_Format(DataColloquio,"%Y")) AS Mese,
Count(*) AS Nr FROM Colloqui
GROUP BY DATE_Format(DataColloquio,"%Y%m"),
CONCAT(MeseInItaliano(DataColloquio)," ",DATE_Format(DataColloquio,"%Y"))
ORDER BY DATE_Format(DataColloquio,"%Y%m");

cs3)
SELECT Voto, Count(*) AS Nr FROM Verifiche
GROUP BY Voto ORDER BY cbyte(Voto)

MYSQL:

SELECT Voto, Count(*) AS Nr FROM Verifiche
GROUP BY Voto ORDER BY CONVERT(Voto,UNSIGNED);

cs4)
SELECT IIf(CByte(Voto)<4,"Gravemente Insufficiente",
IIf(CByte(voto)<6,"Insufficienti","Positivo")) AS Livello, Count(*) AS Nr
FROM Verifiche GROUP BY
IIf(CByte(Voto)<4,"Gravemente Insufficiente",IIf(CByte(voto)<6,"Insufficienti","Positivo"))

MYSQL:

SELECT If(CONVERT(Voto,UNSIGNED)<4,"Gravemente Insufficiente",
If(CONVERT(Voto,UNSIGNED)<6,"Insufficienti","Positivo")) AS Livello, Count(*) AS Nr
FROM Verifiche GROUP BY
If(CONVERT(Voto,UNSIGNED)<4,"Gravemente Insufficiente",If(CONVERT(Voto,UNSIGNED)<6,"Insufficienti","Positivo"));

cs5)
SELECT Count(*) as [Numero Voti], Sum(iif(cbyte(voto)>=6,1,0)) AS [Numero sufficienze],
Format(Sum(iif(cbyte(voto)>=6,1,0))/Count(*),"0.00%") AS [Percentuale Sufficienze]
FROM Verifiche

MYSQL:

SELECT Count(*) as 'Numero Voti', Sum(if(CONVERT(Voto,UNSIGNED)>=6,1,0)) AS 'Numero sufficienze',
CONCAT(FORMAT(100*Sum(if(CONVERT(Voto,UNSIGNED)>=6,1,0))/Count(*),2),"%") AS 'Percentuale Sufficienze'
FROM Verifiche;

cs6)
SELECT DISTINCT TOP 1 CDate(DataVerifica) AS [Giorno dell'ultimo 10]
FROM Verifiche WHERE voto="10"
ORDER BY CDate(DataVerifica) DESC

MYSQL:

SELECT DISTINCT DataVerifica AS 'Giorno dell\'ultimo 10'
FROM Verifiche WHERE voto="10"
ORDER BY STR_TO_DATE(DataVerifica,'%d/%m/%Y') DESC LIMIT 1

cs7)
SELECT iif(instr(QualeGenitore,":")>0,
left(QualeGenitore,instr(QualeGenitore,":")-1),QualeGenitore) AS [Con chi ho parlato],
Count(*) AS Nr FROM Colloqui GROUP BY
iif(instr(QualeGenitore,":")>0,left(QualeGenitore,instr(QualeGenitore,":")-1),QualeGenitore)

MYSQL:

SELECT if(instr(QualeGenitore,":")>0,
left(QualeGenitore,instr(QualeGenitore,":")-1),QualeGenitore) AS 'Con chi ho parlato',
Count(*) AS Nr FROM Colloqui GROUP BY
if(instr(QualeGenitore,":")>0,left(QualeGenitore,instr(QualeGenitore,":")-1),QualeGenitore);

cs8)
SELECT iif(Cdate(DataAssenza)<#1/31/2014#,"1","2") & " Quadrimestre" AS Periodo,
Count(*) As Nr FROM Assenze
Group By iif(Cdate(DataAssenza)<#1/31/2014#,"1","2") & " Quadrimestre"

MYSQL:

SELECT CONCAT(if(STR_TO_DATE(DataAssenza,'%d/%m/%Y')<'2014-01-31','1','2')," Quadrimestre") AS Periodo,
Count(*) As Nr FROM Assenze
Group By CONCAT(if(STR_TO_DATE(DataAssenza,'%d/%m/%Y')<'2014-01-31','1','2')," Quadrimestre");

cs9)
SELECT Count(*) AS [Nr Colloqui], SUM(iif( InStr(QualeGenitore,"Mamma")>0 OR QualeGenitore="Entrambe",1,0)) AS [Nr colloqui con Mamma], SUM(iif( InStr(QualeGenitore,"Papà")>0 OR QualeGenitore="Entrambe",1,0)) AS [Nr colloqui con Papà]
FROM Colloqui;

MYSQL:

SELECT CONCAT(ROUND(100*SUM(if( InStr(QualeGenitore,"Mamma")>0 OR QualeGenitore="Entrambe",1,0))/Count(*),2),'%')
AS `% con Mamma`,
CONCAT(ROUND(100*SUM(if( InStr(QualeGenitore,"Papà")>0 OR QualeGenitore="Entrambe",1,0))/Count(*),2),'%')
AS `% con Papà` FROM Colloqui;

cs10)
SELECT "Classe " &
My_PrimaLetteraMaiuscola(Annata(Classe)) AS [Anno Scolastico],
Count(*) AS [Nr studenti] FROM Studenti
GROUP BY
Annata(Classe), Cbyte(Left(Classe,1))
ORDER BY Cbyte(Left(Classe,1))

MYSQL:

SELECT CONCAT("Classe ",My_PrimaLetteraMaiuscola(Annata(Classe))) AS `Anno Scolastico`,
Count(*) AS `Nr studenti` FROM Studenti
GROUP BY Annata(Classe), CONVERT(Left(Classe,1),UNSIGNED)
ORDER BY CONVERT(Left(Classe,1),UNSIGNED);

ESERCIZIO 4 - IV-M2.5A.4

INTERPRETARE CORRETTAMENTE I SEGUENTI COMANDI MULTI TABELLARI:

ds1)
SELECT Classe, Avg(cbyte(Voto)) AS Media
FROM Verifiche, Studenti
WHERE Verifiche.CodiceStudente=Studenti.CodiceStudente
GROUP BY Classe

MYSQL:

SELECT Classe, Avg(CONVERT(Voto,UNSIGNED)) AS Media
FROM Verifiche, Studenti
WHERE Verifiche.CodiceStudente=Studenti.CodiceStudente
GROUP BY Classe;

ds2)
SELECT iif(Sesso="M","Maschi","Femmine") as Genere, Count(*) AS [Numero Assenze]
FROM Assenze, Studenti
WHERE Assenze.CodiceStudente=Studenti.CodiceStudente
GROUP BY Sesso;

MYSQL:

SELECT if(Sesso="M","Maschi","Femmine") as Genere, Count(*) AS 'Numero Assenze'
FROM Assenze, Studenti
WHERE Assenze.CodiceStudente=Studenti.CodiceStudente
GROUP BY Sesso;

ds3)
SELECT Cognome, Nome, Classe
FROM Studenti LEFT JOIN Verifiche ON Verifiche.CodiceStudente=Studenti.CodiceStudente
WHERE Verifiche.idVerifica is null

MYSQL:

SELECT Cognome, Nome, Classe
FROM Studenti LEFT JOIN Verifiche ON Verifiche.CodiceStudente=Studenti.CodiceStudente
WHERE Verifiche.idVerifica is null;

ds4)
SELECT COUNT(*) as [Nr assenze]
FROM Studenti, Assenze
WHERE Studenti.CodiceStudente = Assenze.CodiceStudente
AND (Studenti.Classe=[Classe di cui si vogliono conoscere le date di assenza])

MYSQL:  utilizzando una variabile che setto all'inizio. Devo convertire il charset della variabile poichè quello utilizzato dalla tabella è latin1.

SET @`Classe di cui si vogliono conoscere le date di assenza`='4T';
SELECT COUNT(*) as `Nr assenze` FROM Studenti, Assenze
WHERE Studenti.CodiceStudente = Assenze.CodiceStudente
AND (Studenti.Classe=CONVERT(@`Classe di cui si vogliono conoscere le date di assenza` USING latin1));

ds5)
SELECT Cognome & " " & Nome & " - " & Classe AS Studente, Materia, Voto, DataVerifica
FROM _CfgSys_Materie, Studenti, Verifiche
WHERE Studenti.CodiceStudente = Verifiche.CodiceStudente
AND [_CfgSys_Materie].idmaterie=verifiche.idmateria

MYSQL:

SELECT CONCAT(Cognome," ",Nome," - ",Classe) AS Studente, Materia, Voto, DataVerifica
FROM _CfgSys_Materie, Studenti, Verifiche
WHERE Studenti.CodiceStudente = Verifiche.CodiceStudente
AND _CfgSys_Materie.idmaterie=verifiche.idmateria;

ds6)
SELECT Cognome, Nome, Sum(iif(isnull(Colloqui.CodiceStudente),0,1)) AS [Nr Colloqui]
FROM Studenti Left JOIN Colloqui ON Studenti.CodiceStudente = Colloqui.CodiceStudente
Group by Cognome,Nome

MYSQL:

SELECT Cognome, Nome, Sum(if(isnull(Colloqui.CodiceStudente),0,1)) AS 'Nr Colloqui'
FROM Studenti Left JOIN Colloqui ON Studenti.CodiceStudente = Colloqui.CodiceStudente
Group by Cognome,Nome;

ds7)
SELECT Cognome, Nome,Count(*) as [Nr Colloqui]
FROM Studenti, Colloqui WHERE Studenti.CodiceStudente = Colloqui.CodiceStudente
Group by Cognome,Nome

MYSQL:

SELECT Cognome, Nome,Count(*) as 'Nr Colloqui'
FROM Studenti, Colloqui WHERE Studenti.CodiceStudente = Colloqui.CodiceStudente
Group by Cognome,Nome;

ds8)
SELECT Classi.Indirizzo, Count(*) AS Nr
FROM Classi, Studenti, Colloqui
WHERE Classi.Classe = Studenti.Classe
AND Studenti.CodiceStudente = Colloqui.CodiceStudente
GROUP BY Classi.Indirizzo;

MYSQL:

SELECT Classi.Indirizzo, Count(*) AS Nr
FROM Classi, Studenti, Colloqui
WHERE Classi.Classe = Studenti.Classe
AND Studenti.CodiceStudente = Colloqui.CodiceStudente
GROUP BY Classi.Indirizzo;

ds9)
SELECT top 1 Studenti.Cognome, Studenti.Nome, Count(*) AS Nr
FROM Studenti, Assenze WHERE Studenti.CodiceStudente = Assenze.CodiceStudente
AND Assenze.AssenzaTattica
GROUP BY Studenti.Cognome, Studenti.Nome
ORDER BY Count(*) DESC;

MYSQL:

SELECT Studenti.Cognome, Studenti.Nome, Count(*) AS Nr
FROM Studenti, Assenze WHERE Studenti.CodiceStudente = Assenze.CodiceStudente
AND Assenze.AssenzaTattica
GROUP BY Studenti.Cognome, Studenti.Nome
ORDER BY Count(*) DESC LIMIT 1;

ds10)
SELECT top 1 Colloqui.QualeGenitore & " di " & Studenti.Cognome & " " & Studenti.Nome AS Chi, Count(*) AS Nr FROM Studenti, Colloqui
WHERE (Studenti.CodiceStudente=Colloqui.CodiceStudente)
GROUP BY Colloqui.QualeGenitore & " di " & Studenti.Cognome & " " & Studenti.Nome
ORDER BY Count(*) DESC;

MYSQL:

SELECT CONCAT(Colloqui.QualeGenitore," di ",Studenti.Cognome," ",Studenti.Nome) AS Chi, Count(*) AS Nr FROM Studenti, Colloqui
WHERE (Studenti.CodiceStudente=Colloqui.CodiceStudente)
GROUP BY CONCAT(Colloqui.QualeGenitore," di ",Studenti.Cognome," ",Studenti.Nome)
ORDER BY Count(*) DESC LIMIT 1;

in mysql LIMIT 1 non è proprio equivalente

SELECT Classe,
       SUM(CASE WHEN Sesso="F" THEN 1 ELSE 0 END) AS Femmine,
       SUM(CASE WHEN Sesso="M" THEN 1 ELSE 0 END) AS Maschi
FROM Studenti GROUP By Classe;

ESERCIZIO 5 - IV-M2.5A.5

INTERPRETARE CORRETTAMENTE I SEGUENTI COMANDI SQL:

MYSQL: In mySql la query incrociata non esiste. La seguente Stored Procedure produce in MySQL un risultato analogo:

-- -----------------------------------------------------
-- STORE PROCEDURE PER EMULARE LE QUERY INCROCIATE
-- -----------------------------------------------------
DROP PROCEDURE IF EXISTS Transform;
DELIMITER $$
CREATE PROCEDURE Transform(stat_func TEXT, stat_arg TEXT,
                           row_select TEXT, row_from TEXT, 
                           col_field TEXT, col_from TEXT, 
                           Decimali TINYINT)

-- L'istruzione DETERMINISTIC indica che la funzione restituirà gli stessi 
-- valori se passo lo stesso set di parametri. MySQL potrà quindi cercare
-- di ottimizzare le performance 
DETERMINISTIC
-- L'istruzione successiva indica che la Stored Proc contiene solo comandi 
-- di lettura dati (SELECT) ma non di scrittura 
READS SQL DATA
-- L'istruzione successiva indica che la Stored Proc dovrà essere eseguita 
-- con i previlegi dell'esecutore (INVOKER) e non del creatore (DEFINER) che
-- rappresenta il default
SQL SECURITY INVOKER

BEGIN
   DECLARE ValoreNullo TEXT;
   SET ValoreNullo = ""; -- Stringa da visualizzare al posto di NULL
   -- Amplio il buffer per il comando GROUP_CONCAT
   SET SESSION group_concat_max_len = 8192;
   -- Evito problemi con il CHARSET sulle variabili locali
   SET character_set_connection = @@character_set_database;
   -- Sistemo alcuni parametri per gestire correttamente la funzione COUNT
   IF (stat_func="COUNT") THEN
      SET stat_func="SUM";
      SET stat_arg="1";
      SET Decimali=-1; -- nel conteggio niente decimali
   END IF;
   -- Creo il testo per costruire l'elenco delle intestazioni di colonna della
   -- query incrociata
   SET @column_query := CONCAT(
                               "SELECT GROUP_CONCAT(DISTINCT CONCAT('\\n, IFNULL(",
                               IF(Decimali>=0,"ROUND(",""),
                               stat_func, 
                               "(CASE WHEN ",
                               col_field,
                               "=', '\"',", 
                               col_field, 
                               ",'\"', ' THEN ",
                               stat_arg,
                               " END)",
                               IF(Decimali>=0,CONCAT(",",Decimali,")"),""),
                               ",''",ValoreNullo,"'') ', CONCAT('`',", 
                               col_field, 
                               ",'`')) SEPARATOR \' \') INTO @TitoliColonne ", 
                               col_from
                              );

   -- L'istruzione successiva serve solo nella fase di debug per verificare la correttezza 
   -- della stringa contenente GROUP_CONCAT
   -- SELECT @column_query;
   -- Con questo comando carico la variabile TitoliColonne
   PREPARE column_query FROM @column_query;
   EXECUTE column_query;
   DEALLOCATE PREPARE column_query;
   -- L'istruzione successiva serve a controllare l'elenco delle intestazioni di colonna ottenute
   -- SELECT @TitoliColonne;

   SET @pivot_query = CONCAT( row_select, @TitoliColonne," ", row_from );
   -- La riga successiva serve per i debug e serve a verificare la query equivalente a quella incrociata
   -- SELECT @pivot_query;
   PREPARE `PivotQry` FROM @pivot_query;
   EXECUTE `PivotQry`;
   DEALLOCATE PREPARE `PivotQry`;

END$$
DELIMITER ;

MYSQL: Il suo utilizzo, partendo dalla sintassi generica della query incrociata ...

TRANSFORM FunzioneStatistica(CampoValore)
SELECT CampoRighe FROM TabellaRighe ...
PIVOT CampoColonne;

MYSQL: ... è il seguente:

Call Trasform("FunzioneStatistica","CampoValore",
              "Select CampoRighe","From TabellaRighe ...",
              "CampoColonne","From TabellaColonne",NrCifreDecimali);

es1)
TRANSFORM Count(*)
SELECT Classe FROM Studenti GROUP BY Classe
PIVOT iif(Sesso="M","Maschi","Femmine");

MYSQL: Come già detto la query incrociata in mysql non esiste. In questo caso, essendo le etichette in testata poche e note a priori ("Maschi" e "Femmine") possiamo ricorrere alla funzione CASE, una per ciascun valore possibile:

SELECT Classe,
       SUM(CASE WHEN Sesso="F" THEN 1 ELSE 0 END) AS Femmine,
       SUM(CASE WHEN Sesso="M" THEN 1 ELSE 0 END) AS Maschi
FROM Studenti GROUP By Classe;

oppure:

SELECT Classe,
       SUM(IF(Sesso="F",1,0)) AS Femmine,
       SUM(IF(Sesso="M",1,0)) AS Maschi
FROM Studenti GROUP By Classe;

oppure utilizzando la stored procedure proposta all'inizio di questa sezione:

CALL Transform('COUNT', '*', 'SELECT Classe', 'FROM Studenti GROUP BY Classe',
'if(Sesso="M","Maschio","Femmina")', 'FROM Studenti',-1);

es2)
SELECT Cognome, Nome, Classe
FROM Studenti WHERE CodiceStudente NOT IN (SELECT CodiceStudente FROM Verifiche);

MYSQL:

SELECT Cognome, Nome, Classe
FROM Studenti WHERE CodiceStudente NOT IN (SELECT CodiceStudente FROM Verifiche);

es3)
SELECT "Gravemente insufficienti" AS Livello, count(*) as Nr from verifiche where cbyte(voto)<4
UNION
SELECT "Insufficienti", count(*) from verifiche where voto="5" or voto="4"
UNION
SELECT "Sufficienti", count(*) from verifiche where cbyte(voto)>=6

MYSQL:

SELECT "Gravemente insufficienti" AS Livello, count(*) as Nr from verifiche where CONVERT(voto,UNSIGNED)<4
UNION
SELECT "Insufficienti", count(*) from verifiche where voto="5" or voto="4"
UNION
SELECT "Sufficienti", count(*) from verifiche where CONVERT(voto,UNSIGNED)>=6;

es4)
SELECT Classi.Classe, Count(*) AS Nr INTO _tmp_Statistica
FROM Classi, Studenti
WHERE Classi.Classe=Studenti.Classe
GROUP BY Classi.Classe

MYSQL:

CREATE TABLE _tmp_Statistica
SELECT Classi.Classe, Count(*) AS Nr
FROM Classi, Studenti
WHERE Classi.Classe=Studenti.Classe
GROUP BY Classi.Classe;

es5)
CREATE TABLE _tmp_EstrazioneStudenti
(
   CodiceStudente LONG CONSTRAINT IdxCodiceStudente PRIMARY KEY,
   Cognome TEXT(35) CONSTRAINT idxCognome NOT NULL,
   Nome TEXT(35),
   Classe TEXT(20) CONSTRAINT idxClasse NOT NULL,
   Sesso TEXT(1),
   RisultatoFinale TEXT(150)
)

MYSQL:

CREATE TABLE _tmp_EstrazioneStudenti
(
   CodiceStudente INT PRIMARY KEY,
   Cognome VARCHAR(35) NOT NULL,
   Nome VARCHAR(35),
   Classe VARCHAR(20) NOT NULL,
   Sesso CHAR(1),
   RisultatoFinale VARCHAR(150)
);

es6)
INSERT INTO _tmp_EstrazioneStudenti
( CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale )
SELECT CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale
FROM Studenti WHERE (Classe="1T");

MYSQL:

INSERT INTO _tmp_EstrazioneStudenti
( CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale )
SELECT CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale
FROM Studenti WHERE (Classe="1T");

es7)
INSERT INTO _tmp_EstrazioneStudenti
( CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale )
VALUES (9999,"Sechi","Marco", "6T", "M","Non ammesso")

MYSQL:

INSERT INTO _tmp_EstrazioneStudenti
( CodiceStudente, Cognome, Nome, Classe, Sesso, RisultatoFinale )
VALUES (9999,"Sechi","Marco", "6T", "M","Non ammesso");

es8)
UPDATE _tmp_EstrazioneStudenti
SET Classe=Cstr(cbyte(left(Classe,1))+1) & Right(Classe,1)
WHERE RisultatoFinale="AMMESSO"

MYSQL:

UPDATE _tmp_EstrazioneStudenti
SET Classe = CONCAT(
                    CONVERT(
                            CONVERT(
                                     CONVERT(left(Classe,1),UNSIGNED)+1,
                                     CHAR
                                   )
                            USING Latin1
                           ),
                    Right(Classe,1)
                   )
WHERE RisultatoFinale="AMMESSO";

es9)
DELETE FROM _tmp_EstrazioneStudenti WHERE Classe like "*T"

MYSQL:

DELETE FROM _tmp_EstrazioneStudenti WHERE Classe like "%T";

es10)
SELECT * FROM _tmp_EstrazioneStudenti
WHERE CodiceStudente<> ALL (SELECT CodiceStudente FROM Studenti)

MYSQL:

SELECT * FROM _tmp_EstrazioneStudenti
WHERE CodiceStudente<> ALL (SELECT CodiceStudente FROM Studenti);

es11)
TRANSFORM Count(*) AS Nr
SELECT Left(classe,1) AS Anno FROM Studenti, Assenze
WHERE (Studenti.CodiceStudente=[Assenze].[CodiceStudente])
GROUP BY Left(classe,1)
PIVOT IIf(CDate(DataAssenza)<#1/31/2014#,"1","2") & " Quadrimestre";

MYSQL: Anche in questo caso, le etichette delle colonne sono limitate a 2 possibili valori: "1°  Quadrimestre" e "2° Quadrimestre" per cui possiamo ricorrere alla funzione IF:

SELECT Left(classe,1) AS Anno,
SUM(IF(STR_TO_DATE(DataAssenza,'%d/%m/%Y')<STR_TO_DATE("31/01/2014",'%d/%m/%Y'),1,0)) AS `1° Quadrimestre`,
SUM(IF(STR_TO_DATE(DataAssenza,'%d/%m/%Y')>=STR_TO_DATE("31/01/2014",'%d/%m/%Y'),1,0)) AS `2° Quadrimestre`
FROM Studenti, Assenze
WHERE (Studenti.CodiceStudente=Assenze.CodiceStudente)
GROUP By Left(classe,1);

oppure utilizzando la stored procedure proposta all'inizio:

CALL Transform('COUNT', '*', 'SELECT Left(classe,1) AS Anno',
'FROM Studenti, Assenze
WHERE (Studenti.CodiceStudente=Assenze.CodiceStudente)
GROUP BY Left(classe,1) ',
'IF( STR_TO_DATE(DataAssenza,"%d/%m/%Y") >= STR_TO_DATE("31/01/2014","%d/%m/%Y"),"1 Quadrimestre","2 Quadrimestre")',
'FROM Assenze',-1);

es12)
TRANSFORM round(Avg(CDbl(VotoIn100esimi)),2) AS [Media Reale]
SELECT
Tassonomia(VotoIn100esimi) AS [Livello voto] FROM Studenti, Verifiche
WHERE (Studenti.codicestudente=Verifiche.codicestudente)
AND
Tassonomia(VotoIn100esimi)<>"NC"
GROUP BY
Tassonomia(VotoIn100esimi), Tassonomia(VotoIn100esimi,"Ordine")
ORDER BY
Tassonomia(VotoIn100esimi,"Ordine")
PIVOT
Annata(Classe);

MYSQL: Le etichette delle colonne sono limitate a 5 possibili valori ("Prima","Seconda", ... e "Quinta") per cui possiamo ricorrere alla funzione CASE:

SELECT Tassonomia(VotoIn100esimi,"Testo") AS 'Livello voto',
ROUND(AVG(CASE WHEN Annata(Classe) = 'prima' THEN VotoIn100esimi END),2) Prima,
ROUND(AVG(CASE WHEN Annata(Classe) = 'seconda' THEN VotoIn100esimi END),2) Seconda,
ROUND(AVG(CASE WHEN Annata(Classe) = 'terza' THEN VotoIn100esimi END),2) Terza,
ROUND(AVG(CASE WHEN Annata(Classe) = 'quarta' THEN VotoIn100esimi END),2) Quarta,
ROUND(AVG(CASE WHEN Annata(Classe) = 'quinta' THEN VotoIn100esimi END),2) Quinta
FROM Studenti, Verifiche
WHERE (Studenti.codicestudente=Verifiche.codicestudente)
GROUP BY Tassonomia(VotoIn100esimi,"Testo")
ORDER BY Tassonomia(VotoIn100esimi,"Ordine");

oppure utilizzando la stored procedure proposta all'inizio:

CALL Transform('AVG', 'VotoIn100esimi',
'SELECT Tassonomia(VotoIn100esimi,"Testo") AS "Livello voto" ',
'FROM Studenti, Verifiche
WHERE (Studenti.codicestudente=Verifiche.codicestudente)
GROUP BY Tassonomia(VotoIn100esimi,"Testo")
ORDER BY Tassonomia(VotoIn100esimi,"Ordine")',
'Annata(Classe)', 'FROM Studenti',2);

es13)
CREATE INDEX NominativoIDX
ON _tmp_EstrazioneStudenti ( Cognome, Nome)
WITH DISALLOW NULL

CREATE INDEX RisultatoFinaleIDX
ON _tmp_EstrazioneStudenti ( RisultatoFinale)
WITH IGNORE NULL

CREATE UNIQUE INDEX ClasseIDX
ON _tmp_Statistica (Classe)
WITH PRIMARY

CREATE INDEX RisultatoFinaleIDX
ON _tmp_EstrazioneStudenti ( RisultatoFinale)
WITH IGNORE NULL

DROP INDEX ClasseIDX ON _tmp_Statistica;

MYSQL: Si osservi che la primary key può essere impostata solo con l'alter table.

ALTER TABLE _tmp_EstrazioneStudenti ADD CHECK ( Cognome <> NULL OR Nome <> NULL );
CREATE INDEX NominativoIDX ON _tmp_EstrazioneStudenti ( Cognome, Nome );

ALTER TABLE _tmp_Statistica ADD PRIMARY KEY (Classe);
CREATE UNIQUE INDEX ClasseIDX ON _tmp_Statistica (Classe);

ALTER TABLE _tmp_EstrazioneStudenti
MODIFY COLUMN RisultatoFinale TINYTEXT DEFAULT NULL;
CREATE INDEX RisultatoFinaleIDX ON _tmp_EstrazioneStudenti (RisultatoFinale(255));

oppure:

ALTER TABLE _tmp_EstrazioneStudenti
ADD INDEX NominativoIDX ( Cognome, Nome ),
ADD CHECK ( Cognome <> NULL OR Nome <> NULL );

ALTER TABLE _tmp_Statistica ADD PRIMARY KEY (Classe), ADD UNIQUE KEY (Classe);

ALTER TABLE _tmp_EstrazioneStudenti
MODIFY COLUMN RisultatoFinale TINYTEXT DEFAULT NULL,
ADD INDEX RisultatoFinaleIDX (RisultatoFinale(255));

infine:

DROP INDEX ClasseIDX ON _tmp_Statistica;

es14)
TRANSFORM Count(*) AS Presenti
SELECT CDate([DataVerifica]) AS [Data Scritto] FROM Studenti, Verifiche
WHERE (Studenti.CodiceStudente=Verifiche.CodiceStudente)
AND (Verifiche.tipologia="Scritto")
AND (DataVerifica & Classe) IN
(
   SELECT (DataVerifica & CLasse) FROM Studenti, Verifiche
   WHERE (Studenti.CodiceStudente=Verifiche.CodiceStudente)
   AND (Verifiche.tipologia="Scritto")
   GROUP BY (DataVerifica & Classe)
   HAVING Count(*) >20
)
GROUP BY CDate(DataVerifica)
ORDER BY CDate(DataVerifica)
PIVOT Studenti.Classe

MYSQL: In questo caso le etichette delle colonne sono tante e non prevedibili a priori pertanto non possiamo ricorrere alla funzione CASE o IF. Possiamo però sfruttare la nostra Stored Procedure per emulare le query incrociate in mysql:

CALL Transform('COUNT', '*', 'SELECT DataVerifica AS `Data Scritto`',
'FROM Studenti, Verifiche
WHERE (Studenti.CodiceStudente=Verifiche.CodiceStudente)
AND (Verifiche.tipologia="Scritto")
AND CONCAT(DataVerifica,Classe) IN
(
   SELECT CONCAT(DataVerifica,Classe) FROM Studenti, Verifiche
   WHERE (Studenti.CodiceStudente=Verifiche.CodiceStudente)
   AND (Verifiche.tipologia="Scritto")
   GROUP BY CONCAT(DataVerifica,Classe)
   HAVING Count(*) >20
)
GROUP BY STR_TO_DATE(DataVerifica,"%d/%m/%Y")
ORDER BY STR_TO_DATE(DataVerifica,"%d/%m/%Y")',
'Classe', 'FROM Studenti', -1);

es15)
ALTER TABLE _tmp_EstrazioneStudenti ADD COLUMN Ripetente BIT;
ALTER TABLE _tmp_EstrazioneStudenti DROP COLUMN Sesso;
ALTER TABLE _tmp_EstrazioneStudenti ALTER COLUMN RisultatoFinale TEXT(160);
DROP TABLE _tmp_EstrazioneStudenti

MYSQL:

ALTER TABLE _tmp_EstrazioneStudenti ADD COLUMN Ripetente BIT;
ALTER TABLE _tmp_EstrazioneStudenti DROP COLUMN Sesso;
ALTER TABLE _tmp_EstrazioneStudenti MODIFY COLUMN RisultatoFinale VARCHAR(160);
DROP TABLE _tmp_EstrazioneStudenti;