Capitolo 3
Funzioni
Le funzioni, nell’ambito dei linguaggi di terza generazioni (linguaggi procedurali), sono delle particolari procedure le quali passandogli dei valori (parametri) esse ci restituiscono (ritornano) un valore.
Anche se SQL non è un linguaggio procedurale, implementa le funzioni nella stessa maniera
ma con una differenza sostanziale:
nei linguaggi procedurali noi stessi possiamo crearci delle funzioni, con SQL ciò non è possibile e quindi possiamo utilizzare solo quelle funzioni che ci mette a disposizione il DBMS che stiamo usando.
In questo capitolo vedremo molte funzioni, ma soltanto le prime 5 (COUNT, SUM, AVG, MAX e MIN) sono definite nello standard SQL. Queste prime cinque funzioni sono le più importanti e dobbiamo impararle bene, esse sono sempre presenti nella maggior parte dei DBMS a differenza delle restanti, che a volte non appaiono affatto o sono implementate con una sintassi diversa.
Le funzioni che analizzeremo in questo paragrafo hanno la particolarità di restituire un solo valore. Inoltre, dato che operano su insiemi di righe, vengono anche chiamate funzioni di gruppo.
Gli esempi di questo paragrafo utilizzano la tabella IMPIEGATO:
IMPIEGATO |
||||
NOME |
COGNOME |
DIPARTIMENTO |
UFFICIO |
STIPENDIO |
MARIO | ROSSI | AMMINISTRAZIONE | 10 | L. 4.500.000 |
CARLO | BIANCHI | PRODUZIONE | 20 | L. 360.000 |
GIUSEPPE | VERDI | AMMINISTRAZIONE | 20 | L. 4.000.000 |
FRANCO | NERI | DISTRIBUZIONE | 16 | L. 4.500.000 |
CARLO | ROSSI | DIREZIONE | 14 | L. 7.300.000 |
LORENZO | LANZI | DIREZIONE | 7 | L. 730.000 |
PAOLA | BORRONI | AMMINISTRAZIONE | 75 | L. 4.000.000 |
MARCO | FRANCO | PRODUZIONE | 46 | L. 4.000.000 |
Restituisce il numero di righe che soddisfano la condizione specificata nella clausola WHERE.
Vediamo un esempio: voglio conoscere il numero di impiegati che appartengono al dipartimento produzione
SELECT COUNT (*)
FROM IMPIEGATO
WHERE DIPARTIMENTO = 'PRODUZIONE';
2 |
Questa funzione somma tutti i valori di una colonna, vediamo un esempio: voglio ottenere la somma di tutti gli stipendi
SELECT SUM(STIPENDIO)
FROM IMPIEGATO;
L.29.390.0000 |
La funzione SUM opera soltanto con i numeri, se viene applicata a un campo non numerico, si ottiene un messaggio di errore.
Calcola la media aritmetica dei valori di una colonna. Vediamo un esempio: voglio conoscere lo stipendio medio della tabella IMPIEGATO.
SELECT AVG(STIPENDIO)
FROM IMPIEGATO;
L. 3.673.750 |
La funzione AVG opera soltanto con i numeri.
Questa funzione serve a trovare il valore massimo di una colonna. Per esempio vogliamo sapere a quanto ammonta lo stipendio maggiore.
SELECT MAX(STIPENDIO)
FROM IMPIEGATO;
L. 7.300.000 |
La funzione MAX opera anche con i caratteri: la stringa ‘Maria’ è maggiore della stringa ‘Giovanna’.
Questa funzione opera in modo analogo a MAX, ad eccezione del fatto che restituisce il valore minimo di una colonna. Per trovare il minimo stipendio della tabella IMPIEGATO si usa la seguente espressione:
SELECT MIN(STIPENDIO)
FROM IMPIEGATO;
L. 360.000 |
La funzione MIN opera anche con i caratteri: la stringa ‘AAA’ è minore della stringa ‘BB’.
Questa funzione calcola la deviazione standard di una colonna di numeri. Non esiste in Access . Vediamo un esempio:
TEMPERATURE |
|
CITTA ------------------------------------- |
TEMPERATURA ------------------------------------ |
ROMA | 10 |
ANCONA | 8 |
NAPOLI | 15 |
SELECT STDDEV(TEMPERATURA)
FROM TEMPERATURE;
STDDEV(TEMPERATURA) -------------------------------------- |
3,6055513 |
VARIANCE
Quadrato della deviazione standard
Questa funzione calcola il quadrato della deviazione standard. Non esiste in Access. Vediamo un esempio usando la tabella usata precedentemente:
SELECT VARIANCE(TEMPERATURA)
FROM TEMPERATURE;
VARIANCE(TEMPERATURA) ------------------------------------- |
13 |
Assiomi delle funzioni aggregate:
Queste funzioni operano su date e orari; sono molto potenti e quando servono si rivelano essere molto utili.
Alcuni DBMS, come Access, non le implementano o usano sintassi diverse.
Questa funzione aggiunge un numero di mesi a una data specificata. Vediamo un esempio usando la tabella sottostante.
PROGETTO |
||
COMPITO ----------------------------------- |
DATA_INIZIO ---------------------------------------- |
DATA_FINE |
AVVIO PROGETTO | 01-Apr-99 |
02-Apr-99 |
DEFINIZIONE SPECIFICHE | 02-Apr-99 |
01-Mag-99 |
CONTROLLO TECNICO | 01-Giu-99 |
30-Giu-99 |
PROGETTAZIONE | 01-Lug-99 |
02-Set-99 |
COLLAUDO | 03-Set-99 |
17-Dic-99 |
SELECT COMPITO, DATA_INIZIO,
ADD_MONTHS(DATA_FINE,2)
FROM PROGETTO;
COMPITO ----------------------------------- |
DATA_INIZIO ---------------------------------------- |
ADD_MONTH |
AVVIO PROGETTO | 01-Apr-99 |
02-Giu-99 |
DEFINIZIONE SPECIFICHE | 02-Apr-99 |
01-Lug-99 |
CONTROLLO TECNICO | 01-Giu-99 |
31-Ago-99 |
PROGETTAZIONE | 01-Lug-99 |
02-Nov-99 |
COLLAUDO | 03-Set-99 |
17-Feb-00 |
Questa funzione fornisce l’ultimo giorno di un mese specificato (se il mese è di 30, 31, 29 o 28 giorni).
SELECT DATA_FINE, LAST_DAY(DATA_FINE)
FROM PROGETTO;
DATA_FINE |
LAST_DAY(DATA_FINE) ----------------------------------- |
02-Apr-99 |
30-Apr-99 |
01-Mag-99 |
31-Mag-99 |
30-Giu-99 |
30-Giu-99 |
02-Set-99 |
30-Set-99 |
17-Dic-99 |
31-Dic-99 |
Questa funzione serve per sapere quanti mesi sono compresi tra il mese x e il mese y.
SELECT COMPITO, DATA_INIZIO, DATA_FINE,
MONTHS_BETWEEN(DATA_FINE, DATA_INIZIO) DURATA
FROM PROGETTO;
COMPITO ----------------------------------- |
DATA_INIZIO ---------------------------------------- |
DATA_FINE |
DURATA --------------- |
AVVIO PROGETTO | 01-Apr-99 |
02-Apr-99 |
,03225806 |
DEFINIZIONE SPECIFICHE | 02-Apr-99 |
01-Mag-99 |
,96774194 |
CONTROLLO TECNICO | 01-Giu-99 |
30-Giu-99 |
,93548387 |
PROGETTAZIONE | 01-Lug-99 |
02-Set-99 |
2,0322581 |
COLLAUDO | 03-Set-99 |
17-Dic-99 |
3,4516129 |
Questa funzione consente di regolare l’ora e la data in funzione del fuso orario. Vediamo un esempio utilizzando la tabella Progetto:
SELECT DATA_FINE AST,
NEW_TIME(DATA_FINE, 'AST' , 'PDT')
FROM PROGETTO;
AST |
NEW_TIME(DATA, ‘AST’, ‘PDT’) |
02-Apr-99 |
01-Apr-99 |
01-Mag-99 |
30-Apr-99 |
30-Giu-99 |
29-Giu-99 |
02-Set-99 |
01-Set-99 |
17-Dic-99 |
16-Dic-99 |
(Vedi le sigle dei fusi orai nella seguente tabella)
FUSI ORARI |
|
SIGLA |
FUSO ORARIO |
AST o ADT | Atlantic Standard o Atlantic Daylight Time |
BST o BDT | Bering Standard o Bering Daylight Time |
CST o CDT | Central Standard o Central Daylight Time |
EST o EDT | Eastern Standard o Eastern Daylight Time |
GMT | Greenwich Mean Time |
HST o HDT | Alaska-Hawaii Standard o Hawaii Daylight Time |
MST o MDT | Mountain Standard o Mountain Daylight Time |
NST | Newfoundland Standard Time |
PST o PDT | Pacific Standard o Pacific Daylight Time |
YST o YDT | Yukon Standard o Yukon Daylight Time |
Questa funzione imposta una nuova data, successiva a quella passatagli come primo parametro, in base al giorno della settimana passatogli come secondo parametro.
SELECT DATA_INIZIO,
NEXT_DAY(DATA_INIZIO, 'VENERDI')
FROM PROGETTO;
DATA_INIZIO ----------------------------- |
NEXT_DAY ----------------------- |
01-Apr-99 |
02-Apr-99 |
02-Apr-99 |
09-Apr-99 |
01-Giu-99 |
04-Giu-99 |
01-Lug-99 |
02-Lug-99 |
03-Set-99 |
10-Set-99 |
Questa funzione fornisce la data e l’ora del sistema. Vediamo degli esempi:
SELECT DISTINCT SYSDATE
FROM PROGETTO;
SYSDATE -------------- |
18-Mar-99 |
Per sapere a che punto del progetto si è arrivati oggi:
SELECT *
FROM PROGETTO
WHERE DATA_INIZIO > SYSDATE;
Si verifica spesso il caso in cui i dati che vengono estrapolati da un database richiedono delle operazioni matematiche. Molte implementazioni di SQL includono delle funzioni aritmetiche simili a queste. Gli esempi esposti si basano sulla tabella Numeri:
NUMERI |
|||
A ----------------------------- |
B ------------------------------------ |
||
3, | 1415 | 4 | |
-45 | ,707 | ||
5 | 9 | ||
-57 | ,667 | 42 | |
15 | 55 | ||
-7 | ,2 | 5 | ,3 |
Questa funzione calcola il valore assoluto del numero specificato. Vediamo un esempio:
SELECT ABS(A)VALORE_ASSOLUTO
FROM NUMERI;
VALORE_ASSOLUTO ----------------------------- |
|
3, | 1415 |
45 | |
5 | |
57 | ,667 |
15 | |
7 | ,2 |
Questa funzione fornisce il più piccolo numero intero che è maggiore o uguale al suo argomento.
Questa sintassi non è implementata da Access.
SELECT A, CEIL(A) MAX_INTERI
FROM NUMERI;
A ----------------------------- |
MAX_INTERI ------------------ |
|
3, | 1415 | 4 |
-45 | -45 |
|
5 | 5 |
|
-57 | ,667 | -57 |
15 | 15 |
|
-7 | ,2 | -7 |
Questa funzione fornisce il più grande numero intero che è minore o uguale al suo argomento.
Questa sintassi non è implementata da Access.
SELECT A, FLOOR(A) MINIMI_INTERI
FROM NUMERI;
A ----------------------------- |
MINIMI_INTERI ------------------ |
|
3, | 1415 | 3 |
-45 | -45 |
|
5 | 5 |
|
-57 | ,667 | -58 |
15 | 15 |
|
-7 | ,2 | -8 |
La funzione SIGN restituisce –1 se il suo argomento è minore di zero e restituisce 1 se il suo argomento è maggiore o uguale a zero. Questa sintassi non è implementata da Access. Vediamo un esempio:
SELECT A, SIGN(A)
FROM NUMERI;
A ----------------------------- |
SIGN(A) ------------------ |
|
3, | 1415 | 1 |
-45 | -1 |
|
5 | 1 |
|
-57 | ,667 | -1 |
15 | 1 |
|
-7 | ,2 | -1 |
È possibile anche utilizzare SIGN in una query SELECT . . . WHERE come questa:
SELECT A
FROM NUMERI
WHERE SIGN(A) = 1;
A ------------- |
3,1415 |
5 |
15 |
Le funzioni trigonometriche COS, SIN, TAN sono molto utili in applicazioni in cui si richiede l’uso di tali calcoli. Tutte queste funzioni operano supponendo che l’angolo n sia espresso in radianti. Queste funzioni, stranamente, sono implementate da Access. Vediamo alcuni esempi usando la tabella ANGOLI:
ANGOLI RADIANTI --------------- |
3,14 |
6,28 |
1,57 |
Calcola il coseno del parametro passatogli come angolo espresso in radianti:
SELECT RADIANTI, COS(RADIANTI)
FROM ANGOLI;
RADIANTI ----------------------- |
COS(RADIANTI) ------------------------------------ |
3,14 |
-,9999987 |
6,28 |
,99999493 |
1,57 |
,00079633 |
Calcola il seno del parametro passatogli come angolo espresso in radianti:
SELECT RADIANTI, SIN(RADIANTI)
FROM ANGOLI;
RADIANTI ----------------------- |
SIN(RADIANTI) ------------------------------------ |
3,14 |
,00159265 |
6,28 |
-,0031853 |
1,57 |
,99999968 |
Calcola la tangente del parametro passatogli come angolo espresso in radianti:
SELECT RADIANTI, TAN(RADIANTI)
FROM ANGOLI;
RADIANTI ----------------------- |
TAN(RADIANTI) ------------------------------------ |
3,14 |
-,0015927 |
6,28 |
-,0031853 |
1,57 |
1255,7656 |
Funzioni sulle potenze, logaritmi e radici
Per gli esempi verrà usata la tabella NUMERI sottostante:
NUMERI |
|||
A ----------------------------- |
B ------------------------------------ |
||
3, | 1415 | 4 | |
-45 | ,707 | ||
5 | 9 | ||
-57 | ,667 | 42 | |
15 | 55 | ||
-7 | ,2 | 5 | ,3 |
Questa funzione permette di elevare e a un esponente (e è una costante matematica che viene utilizzata in varie formule). Vediamo un esempio:
SELECT A, EXP(A)
FROM NUMERI;
A ----------------------------- |
EXP(A) ------------------------------------ |
||
3, | 1415 | 23 | ,138549 |
-45 | 2 | ,863E-20 | |
5 | 148 | ,41316 | |
-57 | ,667 | 9 | ,027E-26 |
15 | 3269017 | ,4 | |
-7 | ,2 | ,00074659 |
Questa funzione calcola il logaritmo naturale. Questa funzione non è implementata da Access .
Vediamo un esempio in cui si vuole calcolare i logaritmi della colonna A della tabella NUMERI:
SELECT A, LN(A)
FROM NUMERI;
ERRORE:
ORA-01428: l'argomento '-45' è esterno all'intervallo
Il messaggio d’errore che viene visualizzato è dato dal fatto che non è possibile determinare un logaritmo di un valore negativo quando la base è positiva: non esiste nessun esponente che elevato ad e (valore positivo) ci da come risultato un valore negativo.
Il ‘problema’ può essere risolto inserendo all’interno della funzione LN la funzione ABS che ci restituisce i valori assoluti di quelli specificati:
SELECT A, LN(ABS(A))
FROM NUMERI;
A ----------------------------- |
LN(ABS(A)) ------------------ |
|
3, | 1415 | 1,1447004 |
-45 | 3,8066625 |
|
5 | 1,6094379 |
|
-57 | ,667 | 4,0546851 |
15 | 2,7080502 |
|
-7 | ,2 | 1,974081 |
Questa funzione richiede due argomenti e calcola il logaritmo del secondo avendo come base il primo. Vediamo un esempio in cui si calcolano i logaritmi del numero 2 aventi come base i valori della colonna B della tabella NUMERI:
SELECT B, LOG(B, 2)
FROM NUMERI;
B ------------------------------------ |
LOG(B,2) ----------------------------------------- |
||
4 | ,5 | ||
,707 | -1 | ,999129 | |
9 | ,31546488 | ||
42 | ,18544902 | ||
55 | ,17296969 | ||
5 | ,3 | ,41562892 |
Questa funzione non ci permette, però, di calcolare il logaritmo in cui la base è negativa, dunque il primo argomento che viene passato alla funzione dovrà essere sempre maggiore di zero.
Questa funzione non è implementata da Access. Questa funzione consente di elevare un numero alla potenza di un altro. Il primo argomento è elevato alla potenza del secondo. Vediamo un esempio:
SELECT A, B, POWER(A, B)
FROM NUMERI;
ERRORE:
ORA-01428: l'argomento '-45' è esterno all'intervallo
Sembrerebbe che non sia possibile (matematicamente) elevare un valore negativo ad un indice frazionario, ma non è così, il problema dunque sussiste forse solamente per SQL implementato da Oracle. Il problema può essere risolto usando opportune funzioni viste in precedenza o evitando di far calcolare la potenza di un numero negativo usando un indice frazionario. Facciamo un’altra prova:
SELECT A, B, POWER(B, A)
FROM NUMERI;
A ------------------------- |
B ------------------- |
POWER(B,A) ----------------- |
||
3, | 1415 | 4 | 77,870231 |
|
-45 | ,707 | 5972090,5 |
||
5 | 9 | 59049 |
||
-57 | ,667 | 42 | 2,467E-94 |
|
15 | 55 | 1,275E+26 |
||
-7 | ,2 | 5 | ,3 | 6,098E-06 |
Questa funzione è implementata da Access con la sintassi ‘SQR(nome_campo)’. La funzione SQRT restituisce la radice quadrata di un argomento. Poiché la radice quadrata di un numero negativo non esiste, non è possibile utilizzare questa funzione con i numeri negativi.
Vediamo una esempio:
SELECT B, SQRT(B)
FROM NUMERI;
B |
SQRT(B) |
4 |
2 |
,707 |
,84083292 |
9 |
3 |
42 |
6,4807407 |
55 |
7,4161985 |
5,3 |
2,3021729 |
Queste funzioni ci permettono di manipolare i dati da visualizzare in tutti i modi e formati desiderati. Sono particolarmente utili quando abbiamo la necessità di rendere i dati più leggibili o quando vogliamo estrapolare delle informazioni sulle stringhe e i caratteri rappresentanti le informazioni.
Gli esempi presentati si basano sulla tabella CARATTERI sottostante:
CARATTERI |
|||
COGNOME |
NOME |
S |
CODICE |
ROSSI | GIGI | A |
32 |
BIANCHI | MARIO | J |
67 |
NERI | MARIA | C |
65 |
BRUNI | ANGELO | M |
87 |
SCURI | ANNA | A |
77 |
VERDI | ANTONIO | G |
52 |
Questa funzione fornisce il carattere corrispondente al codice ASCII passatogli. Vediamo un esempio:
SELECT CODICE, CHR(CODICE)
FROM CARATTERI;
CODICE ------------------------- |
CH ----------- |
32 | |
67 | C |
65 | A |
87 | W |
77 | M |
52 | 4 |
pag. 5 di 20 |