I costrutti del Transact SQL
Avrete già capito che il T-SQL va ben oltre le funzionalità dell'SQL standard. Difatti con il T-SQL possiamo fare esercizio di vera e propria programmazione come in C++ o Visual Basic. Programmare in T-SQL significa sostanzialmente progettare e creare stored procedure (che analizzeremo in dettaglio più avanti) che rappresentano i veri programmi creati con il T-SQL.
Per questo motivo è fondamentale comprendere bene tutti gli elementi trattati
in di questa lezione: le VARIABILI, il costrutto per il controllo del flusso IF ELSE e quello del loop WHILE.
Lavorare con le variabili
In precedenza abbiamo parlato dei datatype (tipi di dati). Ogni
variabile utilizzata all'interno di una stored procedure (o di un batch) deve
essere dichiarata assieme al suo datatype attraverso una istruzione DECLARE ed in seguito possiamo assegnarle un valore attraverso una istruzione SET o SELECT.
Vediamo alcuni esempi su come possiamo dichiare variabili:
Su linea singola:
DECLARE @VARIABILE_TESTO AS VARCHAR(300)
oppure su più linee (è il parser ad occuparsi della verifica delle istruzioni)
DECLARE
@VARIABILE_NUMERO AS INTEGER,
@VARIABILE_TESTO AS CHAR(300),
@ VARIABILE_TESTOUNICODE NVARCHAR(500)
la sintassi con cui dichiariamo le variabili può essere riportata allo schema
seguente:
DECLARE {@variabile_locale [AS] tipo_dato}
[,...;n]
Come potete osservare il nome delle variabili deve iniziare con il simbolo
"at" (@ ) e seguire le regole standard per gli identificatori (sono permessi
caratteri alfanumerici e simboli come _ , @ , $ e # ), la parola chiave AS opzionale. Al contrario di altri linguaggi come il C++ od altri nel T-SQL non è possibile dichiarare costanti.
In T-SQL le variabili debbono interdersi come variabili locali, cioè hanno significato solo all'interno del batch (gruppo o sequenza di istruzioni T-SQL) o della stored procedure nella quale vengono dichiarate , fuori da questo contesto perdono significato. E' possibile passare variabili da una procedura ad un'altra.
Convenzioni per i nomi delle variabili
E' utile trovare a livello aziendale o personale delle convezioni nell'assegnazione dei nomi alle variabili.
Generalmente, dove è possibile, è bene far coincidere i nomi delle variabili
con i nomi delle colonne delle tabelle. Altra regola utile è dare nomi combinati
alle variabili, dove necessario. Ad esempio nel caso di un campo Descrizione
nella tabella News, al quale vogliamo far riferimento con due variabili per avere la descrizione completa e quella breve (ad esempio i primi 50 caratteri) potremmo scrivere:
DECLARE @DescrizioneBreve CHAR(50), @DescrizioneEstesa CHAR(255)
Altrettanto comodo è scegliere delle convenzioni nello stile di scrittura delle variabili. Tutte in maiuscolo oppure minuscolo, usare il carattere _ come separatore oppure no ?
Questi dilemmi possono essere risolti a seconda delle preferenze del programmatore, ecco una piccola panoramica delle possibilità:
DECLARE @MiaVariabile Varchar(500)
DECLARE @Mia_Variabile varchar(500)
DECLARE @MIA_VARIABILE VARCHAR(500)
Assegnare i valori alle variabili
Come abbiamo anticipato per assegnare un valore ad una variabile dopo averla
dichiarata dobbiamo usare una istruzione SET o SELECT, la cui sintassi è la
seguente:
SELECT { @ variabile_locale = espressione } [ ,...n ]
L'espressione può essere una qualsiasi altra variabile un numero , una stringa, una data oppure il valore risultante dalla chiamata di altre funzioni valide per SQL Server (GETDATE(),@@VERSION, ecc...).
Ovviamente possiamo recuperare valori dall'interno delle tabelle dei nostri
databases, vediamo il codice qui sotto:
1 - Listato assegnazione valore da riga singola
/* Dichiaro la variabile */
DECLARE @au_lname AS CHAR(20)
/* Inizializzo la variabile */
SET @au_lname = ''
/* Recupero il valore e lo assegno con una istruzione SELECT */
SELECT @au_lname = au_lname FROM authors WHERE au_id = 'aaa-aaa-aaa'
/* Stampo il valore che ho precedentemente recuperato */
PRINT @au_lname
In questo caso specificando nella condizione WHERE il valore della chiave primaria au_id siamo certi che il valore recuperato sia sicuramente univoco, cioè quello contenuto esattamente nella riga indicata.
Ma cosa accadde quando vengono recuperate più righe? Facciamo un esempio:
2 - Listato assegnazione valore da riga multipla
/* Dichiaro la variabile */
DECLARE @au_lname AS CHAR(20)
/* Inizializzo la variabile */
SET @au_lname = ''
/* Recupero il valore e lo assegno con una istruzione SELECT */
SELECT @au_lname = au_lname FROM authors
/* Stampo l'ultimo valore che ho precedentemente recuperato */
PRINT @au_lname
In questo caso tra le n righe recuperate dall'istruzione SELECT, all'interno
della variabile scalare @au_lname sarà memorizzato solamente quello dell'ultima
riga recuperata. SQL Server procede in questo modo: la variabile viene aggiornata continuamente ad ogni singola recuperata, ma ovviamente i precedenti valori vengono cancellati dai successivi.
Per avere memoria dei precedenti può essere utile una operazione simile:
3 - Listato concatenazione di più valori all'interno di una variabile
/* Dichiaro la variabile */
DECLARE @au_lname AS VARCHAR(8000)
/* Inizializzo la variabile */
SET @au_lname = ''
/* Recupero i valori dei campi au_lname e li concateno tra loro con una istruzione SELECT */
SELECT @au_lname = @au_lname + ',' + au_lname FROM authors
/* Stampo la stringa contente tutti i valori del campo au_lname */
PRINT @au_lname
Il risultato sarà simile a questo: ,Bennet,Blotchet-Halls,Carson,DeFrance,del
Castillo,Dull,Green
Nei listati precedenti dopo la dichiarazione della variabile avviene sempre
la sua inizializzazione, questa è cosa buona perché altrimenti la variabile
avrebbe un valore null di default. Il valore null deve essere trattato con molta
cura perché potrebbe trarre in inganno.
Prendiamo come esempio il listato della concatenazione il numero 3, provate
a commentare o togliere la linea dell'inizializzazione della variabile:
/* Inizializzo la variabile */
-- SET @au_lname = '' -- aggiungo un commento
Il risultato come osserverete cambia enormemente, difatti la stampa del contenuto della variabile produce un output nullo pur avendo valori corretti all'interno delle righe che abbiamo concatenato! Perché?
Semplice, non inizializzando la variabile @au_lname a vuota (operazione che
facciamo con i doppi apici) essa si trova di default con un valore nullo all'interno e quindi per la compatibilità con lo standard ANSI 92 SQL Server setta a null le stringhe a cui vengono concatenati valori nulli.
Volendo possiamo disattivare questa opzione, basta impostare con una istruzione SET il flag CONCAT_NULL_YIELDS_NULL a OFF (di default è su ON), il listato 3 potrebbe quindi anche essere riscritto (abbandonando però la compatibilità con lo standard) in questo modo:
/* Disattivo il flag */
SET CONCAT_NULL_YIELDS_NULL OFF
/* Dichiaro la variabile */
DECLARE @au_lname AS VARCHAR(8000)
/* Recupero i valori dei campi au_lname e li concateno tra loro con una istruzione SELECT */
SELECT @au_lname = @au_lname + ',' + au_lname FROM authors
NB. Questa opzione funziona esclusivamente a livello di sessione o della singola stored procedure in cui è attivata, ma se decidete di adottarla permanentemente potete attivarla per l'intero database sul quale lavorate attraverso l'istruzione:
ALTER DATABASE SET CONCAT_NULL_YIELDS_NULL
oppure usando sp_dboption con il paramentro "CONCAT_NULL_YIELDS_NULL"
Vi chiederete ora quale sia la differenza fra un SET e una SELECT, SET può assegnare solo una variabile alla volta mentre la SELECT anche più variabili.
Vediamo un altro caso interessante per studiare il comportamento di SQL Server nell'assengnamento dei valori alle variabili:
/* Dichiaro la variabile */
DECLARE @au_lname AS CHAR(20)
/* Inizializzo la variabile con il mio nome*/
SET @au_lname = 'Luca Milan'
/*
Recupero il valore e lo assegno con una istruzione SELECT
Da notare l'istruzione SELECT non recupera nessun valore
Perchè l'au_id '000-000-000' non esiste nella tabella
*/
SELECT @au_lname = au_lname FROM authors WHERE au_id = '000-000-000'
/* Stampo il valore della variabile */
PRINT @au_lname
Quale sarà il valore stampato a video da SQL? Forse vi stupirà ma il risultato 'Luca Milan', cioè la stringa con cui ho inizializzato la variabile. SQL server quando recupera righe vuote da una SELECT assegna alla variabile il valore che aveva prima dell'istruzione SELECT usata per l'assegnazione, in questo caso il mio nome.