Appunti (tentativo di fare un manuale) su
SQL con la spiegazione di cosa si intende con
database e tabelle.
Vengono trattate le istruzioni
SELECT,
INSERT,
UPDATE e
DELETE.
Terminologia
Definiamo cosa si intende con il termine
Database relazionale. Con Database (DB) si intende un insieme di dati memorizzati e correlati logicamente fra loro. A questi dati si può accedere attraverso vari strumenti e in multiutenza (più accessi in contemporanea). Questo tipo di database viene indicato con la sigla
RDBMS ovvero
Relational Database Management System.
Per meglio organizzare i dati all'interno di un database questi vengono raggruppati in Tabelle. Vediamo un esempio di tabella:
Tabella_1
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Paperopoli | A1010 | 1001 34567 |
2 | Paperone | De Paperoni | Paperopoli | A1021 | 1001 98752 |
4 | Topolino | Toponi | Topolinia | A1030 | 1002 38988 |
Come si vede una tabella è composta da colonne e righe, chiamate
record, e le loro intersezioni vengono definite
campiI titoli in grassetto sono i nomi dei campi che vengono usati (vedremo dopo come) per farsi ritornare il valore corrispondente all'intersezione della colonna e della riga corrente.
Ogni colonna della tabella può rappresentare un solo tipo di dati. Per tipo di dati intendiamo il valore che potranno contenere. Ovvero ogni colonna potrà contenere, in base a come viene definita, i seguenti valori:
- valori stringa identificati come CHAR / VARCHAR / STRING, es.: 'Alberto'
- valori numerici identificati come NUMERIC / FLOAT / MONEY / INTGER, es.: 1 1.2
- valori data e/o ora identificati come DATETIME, es.: 25-02-2004 22.51.00
- valori binari (BLOB Binary Large Object) identificati come MEMO / BYNARY / TEXT, es.: immagini o file
questi sono solo alcuni tipi di dato gestiti da SQLServer, altri database possono avere più o meno tipi di dato e/o identificati in modo diverso.
Per accedere ai dati contenuti in un DB viene utilizzato il linguaggio di interrogazione
SQL ovvero
Structured Query Language (in origine chiamato SEQUEL Structured English Query Language), standardizzato dall'istituto ANSI (American National Standards Institute) nel 1986, 89, 92 (chiamato anche SQL2 o SQL92) e infine nel 1999 (SQL3 o SQL99). La maggior parte dei DB è conforme, solitamente in parte, con lo standard SQL92, anche se ogni produttore introduce delle varianti/aggiunte/personalizzazioni. In ogni caso le istruzioni che vedremo in questo manuale
dovrebbero andare bene per tutti i DB.
Linguaggio SQL
Il linguaggio SQL si divide in tre gruppi principali di istruzioni:
- DDL Data Definition Language ovvero linguaggio di definizione dei dati: usato per la creazione e la definizione della struttura del DB
- DML Data Manipulation Language ovvero linguaggio di manipolazione dei dati: usato per recuperare/modificare i dati dalle tabelle/oggetti
- DCL Data Control Language ovvero linguaggio di controllo dei dati: usato gestire le autorizzazioni degli utenti sugli tabelle/oggetti
Non analizzeremo per ora il DDL in quanto quasi tutti i DB mettono a disposizione degli strumenti visuali per la gestione del DB o la creazione/modifica/cancellazione di Tabelle.
Andremo invece ad analizzare il DML, in quanto è (quasi) l'unica via per gestire i dati da un qualsiasi linguaggio di programmazione e soprattutto è uno standard riconosciuto e adottato da tutti i DB.
Data Manipulation Language (DML)
All'interno del DML possiamo fare una macro suddivisione di 4 istruzioni che permettono di fare tutte le operazioni necessarie relative a una o più tabelle. Queste istruzioni sono:
- SELECT per estrarre dati dalle tabelle
- INSERT per inserire un record in una tabella
- UPDATE per modificare uno o più record di una tabella
- DELETE per cancellare uno o più record da una tabella
Per seguire gli esempi ti consiglio di utilizzare
Query Analizer, con cui potrai
creare la Tabella_1 (in fondo all'articolo trovi il codice) e seguire gli esempi riportati.
Vediamo la struttura del comando SELECT
SELECT <elenco campi separato da virgole>
FROM <nome della tabella>
WHERE <condizione di selezione>
ORDER BY <elenco campi separato da virgola>
Dove tutto l'insieme viene definito comando o istruzione SQL mentre le singole keyword (es. SELECT, FROM, ecc...) vengono definite clausole e gli argomenti tra i simboli maggiore e minore sono definiti modificatori.
Le uniche clausole che sono sempre presenti sono SELECT e FROM, mentre le altre sono opzionali, ma quando presenti devono essere nell'ordine visualizzato.
Il comando SELECT prevede altre clausole che vedremo successivamente.
La forma più semplice di utilizzo è la seguente:
Che applicata alla tabella vista prima (Tabella_1) restituisce tutti i campi (l'asterisco indica tutti i campi della tabella) .
Se non servono tutti i campi della tabella, si possono specificare i nome dei campi che si vuole estrarre:
SELECT [nome], [cognome]
FROM Tabella_1
Restituisce solo le colonne identificate dal nome: 'nome' e 'cognome', ovvero:
Nome | Cognome |
Paperino | Paolino |
Paperone | De Paperoni |
Topolino | Toponi |
Nel caso non volessi farmi restituire tutti i record della tabella (nel caso precedente 3 record / righe), devo usare la clausola WHERE per selezionare solo i record che interessano.
Facciamo un esempio, supponiamo di volere estrarre i campi nome, cognome e telefono di tutti gli abitanti di 'paperopoli':
SELECT [nome], [cognome], [telefono]
FROM Tabella_1
WHERE [città] = 'paperopoli'
Nome | Cognome | Telefono |
Paperino | Paolino | 1001 34567 |
Paperone | De Paperoni | 1001 98752 |
A questo punto è necessario fare alcune precisazioni.
Nella Tabella_1 il nome di città 'Paperopoli' è stato inserito con la prima lettere in maiuscolo, mentre nella clausola WHERE è stato scritto 'paperopoli' con la prima lettera minuscola. Questo perché il DB preso in considerazione (SQL Server) è case-insensitive ovvero non fa differenza tra maiuscole e minuscole (in realtà dipende da come viene installato). Altri DB invece sono case-sensitive, es.: AS/400.
Inoltre dato che il campo 'città' o di tipo carattere, il valore nella clausola WHERE è stato racchiuso tra apici singoli. Se fosse stato di tipo numerico gli apici non andavano messi.
Esempio
SELECT [id], [nome], [cognome], [telefono]
FROM Tabella_1
WHERE [id] >= 2
id | Nome | Cognome | Telefono |
2 | Paperone | De Paperoni | 1001 98752 |
4 | Topolino | Toponi | 1002 38988 |
Gli
operatori di confronto disponibili sono: = , >= , <= , !=
Nel caso si dovesse testare se un campo contiene il valore
null si usa l'oeratore
IS. Esempio:
SELECT [id], [nome], [cognome], [telefono]
FROM Tabella_1
WHERE [telefono] IS null
che non ritorna niente in quanto nell'esempio non c'è nessun campo con valore null.
Supponiamo adesso di voler ordinare la tabella per 'cognome' in ordine ascendente:
SELECT [nome], [cognome], [telefono]
FROM Tabella_1
WHERE [città] = 'paperopoli'
ORDER BY [cognome]
id | Nome | Cognome | Telefono |
2 | Paperone | De Paperoni | 1001 98752 |
1 | Paperino | Paolino | 1001 34567 |
Oppure discendente
SELECT [nome], [cognome], [telefono]
FROM Tabella_1
WHERE [città] = 'paperopoli'
ORDER BY [cognome] DESC
id | Nome | Cognome | Telefono |
1 | Paperino | Paolino | 1001 34567 |
2 | Paperone | De Paperoni | 1001 98752 |
Posso anche usare delle condizioni di rcerca (clausola WHERE) più complesse usando gli operatori logici AND e OR. Esempio:
SELECT [id], [nome], [cognome], [città], [telefono]
FROM Tabella_1
WHERE [nome] = 'paperino' OR [id]=4
id | Nome | Cognome | Città | Telefono |
1 | Paperino | Paolino | Paperopoli | 1001 34567 |
2 | Paperone | De Paperoni | Paperopoli | 1001 98752 |
4 | Topolino | Toponi | Topolinia | 1002 38988 |
Ovvero, estai tutte le righe dove il campo 'nome' contiene 'paperino' oppure il campo 'id' contiene il valore 4. Quindi basta che sia soddisfatta almeno una delle condizioni perché la riga venga restituita. Al contrario l'operatore AND richiede che entrambi le condizioni siano soddisfatte contemporaneamente. Esempio:
SELECT [id], [nome], [cognome], [città], [telefono]
FROM Tabella_1
WHERE [id] > 1 AND [cognome]= 'toponi'
id | Nome | Cognome | Città | Telefono |
4 | Topolino | Toponi | Topolinia | 1002 38988 |
Come si può vedere in questo caso sia il record con 'id' 2 e 4 soddisfa la prima condizione, ma solo nel record con 'id' uguale a 4 abbiamo anche (ovvero contemporaneamente) il campo 'cognome' uguale a 'toponi'.
Gli
operatori logici disponibili sono: AND , OR e NOT
Per quanto riguarda i campi stringa esistono anche altri operatori. Uno molto potente e flessibile è l'operatore 'LIKE'. Questo permette di fare delle ricerche parziali all'interno dei campi.Esempio
SELECT [id], [nome], [cognome], [città], [telefono]
FROM Tabella_1
WHERE [nome] LIKE 'pap%'
id | Nome | Cognome | Città | Telefono |
1 | Paperino | Paolino | Paperopoli | 1001 34567 |
2 | Paperone | De Paperoni | Paperopoli | 1001 98752 |
Il simbolo '%' (percentuale, detto anche carattere jolly, che su altri DB può essere sostituito da '*' asterisco) indica nessuno o più caratteri. Ovvero vengono ricercate tutte le parole che iniziano con 'pap'. Quindi andrà bene 'pap', 'pap1', 'paperone', 'paperino'. Ecc…
Un altro carattere jolly è '?' (punto di domanda) che indica nessuno o al massimo un carattere qualsiasi. Esempio:
SELECT [id], [nome], [cognome], [città], [cod], [telefono]
FROM Tabella_1
WHERE [cod] LIKE 'A10?0'
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Paperopoli | A1010 | 1001 34567 |
4 | Topolino | Toponi | Topolinia | A1030 | 1002 38988 |
Il record con 'id' uguale a 2 non viene restituita in quanto l'ultimo carattere del campo 'cod' è uguale a '1'.
Un altro operatore molto interessante è 'IN' , che permette di specificare una serie di valori. Vediamo un esempio:
SELECT [id], [nome], [cognome], [città], [cod], [telefono]
FROM Tabella_1
WHERE [nome] IN ( 'Paperino', 'Topolino')
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Paperopoli | A1021 | 1001 98752 |
4 | Topolino | Toponi | Topolinia | A1030 | 1002 38988 |
Vediamo la struttura del comando INSERT
INSERT <nome della tabella> (<elenco campi separato da virgole>)
VALUES (<elenco valori>)
Dove tutte le clausole sono sempre presenti e obbligatorie. Le parentesi tonde sono anch'esse obbligatorie.
Adesso vediamo degli esempi in cui andremo ad inserire dei valori nella tabella:
INSERT Tabella_1 ([id], [nome], [cognome], [città], [cod], [telefono])
VALUES (5, 'pippo', 'de pippis', 'topolinia', 'B1030', '1002 345345')
Modifica la tabella ma non ritorna nessun risultato, per vedere le modifiche apportate digitare:
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Paperopoli | A1010 | 1001 34567 |
2 | Paperone | De Paperoni | Paperopoli | A1021 | 1001 98752 |
4 | Topolino | Toponi | Topolinia | A1030 | 1002 38988 |
5 | pippo | de pippis | topolinia | B1030 | 1002 345345 |
A riguardo del comando INSERT non c'è molto da dire in quanto l'unica sintassi è quella mostrata. Bisogna solo fare attenzione (come con tutti gli altri comandi) a racchiudere i valori stringa all'interno delle virgolette singole e specificare i valori dei campi con lo stesso ordine con cui sono stati specificati i nomi dei campi.
Vediamo la struttura del comando UPDATE
UPDATE <nome della tabella> SET
<nome campo 1> = <valore campo 1>,
<nome campo 2> = <valore campo 2>,
. . .
<nome campo n> = <valore campo n>
WHERE <condizione di selezione>
Dove tutte le clausole sono sempre presenti e obbligatorie ad eccezione di WHERE, in questo caso le modifiche avranno effetto su tutta la tabella. Le virgole separano le coppie nome campo e valore.
Adesso vediamo degli esempi in cui andremo a modificare alcuni valori in alcuni record della tabella:
UPDATE Tabella_1 SET
[cognome] = 'de topis',
[cod] = 'B1031
WHERE [id] = 4
Modifica la tabella ma non ritorna nessun risultato, per vedere le modifiche apportate digitare:
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Paperopoli | A1010 | 1001 34567 |
2 | Paperone | De Paperoni | Paperopoli | A1021 | 1001 98752 |
4 | Topolino | de topis | Topolinia | B1031 | 1002 38988 |
5 | pippo | de pippis | topolinia | B1030 | 1002 345345 |
Anche riguardo del comando
UPDATE non c'è molto da dire in quanto l'unica sintassi è quella mostrata. Le uniche cosa da sottolineare sono che, a differenza del comando
INSERT, non è necessario specificare tutti i campi ma solo quelli che si vogliono aggiornare. Inoltre il comando
UPDATE può agire contemporaneamente su più record. Esempio
UPDATE Tabella_1 SET
[città] = 'Mondo Disney'
WHERE [città] = 'paperopoli'
SELECT *
FROM Tabella_1
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Mondo Disney | A1010 | 1001 34567 |
2 | Paperone | De Paperoni | Mondo Disney | A1021 | 1001 98752 |
4 | Topolino | de topis | Topolinia | B1031 | 1002 38988 |
5 | pippo | de pippis | topolinia | B1030 | 1002 345345 |
Dove sono stati aggiornati contemporaneamente i record con 'id' uguale a 1 e 2, ovvero dove il campo città conteneva 'paperopoli'
Vediamo la struttura del comando DELETE
DELETE <nome della tabella>
WHERE <condizione di selezione>
Dove tutte le clausole sono sempre presenti e obbligatorie ad eccezione di
WHERE, in questo caso le modifiche avranno effetto su tutta la tabella.
Adesso vediamo degli esempi in cui andremo a cancellare alcuni record della tabella:
DELETE Tabella_1
WHERE [id] = 2
Modifica la tabella ma non ritorna nessun risultato, per vedere le modifiche apportate digitare:
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Mondo Disney | A1010 | 1001 34567 |
4 | Topolino | de topis | Topolinia | B1031 | 1002 38988 |
5 | pippo | de pippis | topolinia | B1030 | 1002 345345 |
Anche riguardo del comando
DELETE non c'è molto da dire in quanto l'unica sintassi è quella mostrata. Come con il comando UPDATE è possibile agire su più record contemporaneamente. Esempio:
DELETE Tabella_1
WHERE left([cod], 1) = 'B'
Modifica la tabella ma non ritorna nessun risultato, per vedere le modifiche apportate digitare:
id | Nome | Cognome | Città | COD | Telefono |
1 | Paperino | Paolino | Mondo Disney | A1010 | 1001 34567 |
In questo caso abbiamo usato anche una nuova funzione
LEFT che, nello specifico esempio, ritorna 1 carattere del campo a partire da sinistra, se coincide con 'B' la condizione è vera e la riga viene eliminata. Avremmo anche potuto usare l'operatore LIKE visto prima per raggiungere lo stesso risultato:
DELETE Tabella_1
WHERE [cod] LIKE 'B%'
Altre funzioni simili sono:
- RIGHT(<nome campo>, <numero caratteri>) : ritorna i caratteri partendo da destra
- SUBSTRING(<nome campo>, <start>, <length>) : ritorna <length> caratteri a partire dal carattere <start>
- CHARINDEX(<nome campo>, <str>, <start>) : ritorna la posizione in cui si trova la stringa <nome campo> all'interno della stringa <str> iniziando la ricerca dal carattere <start>
- LEN(<nome campo>) : che ritorna la lunghezza, in caratteri, del campo
- LTRIM(<nome campo>) : ritorna una stringa senza spazi a sinistra
- RTRIM(<nome campo>) : ritorna una stringa senza spazi a DESTRA
- LOWER(<nome campo>) : ritorna una stringa con tutti i caratteri in minuscolo
- UPPER(<nome campo>) : ritorna una stringa con tutti i caratteri in maiuscolo
- e molte altre...
Conclusioni
Come si è visto i comandi fondamentali sono solo 4 e quasi tutti hanno in comune (a parte
INSERT) la clausola WHERE per selezionare un certo insieme di record.
Quello che abbiamo visto finora sono i comandi SQL con una sintassi di base, nella pratica, soprattutto il comando SELECT, ha molte più clausole che permettono di fare delle interrogazioni più complesse mettendo in relazione più tabelle tra loro oltre a tutti i comandi del gruppo DDL per creare, modificare o eliminare tabelle o più in generale per intervenire sulla struttura del DB.
Per ora è tutto.
Il codice sql per creare la tabella usata in questo articolo:
CREATE TABLE [dbo].[Tabella_1] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[Nome] [varchar] (50) NOT NULL ,
[Cognome] [varchar] (50) NOT NULL ,
[Città] [varchar] (50) NOT NULL ,
[COD] [char] (10) NOT NULL ,
[Telefono] [varchar] (50) NOT NULL
)
GO
INSERT INTO [Tabella_1] ([Nome], [Cognome], [Città], [COD], [Telefono])
VALUES('Paperino', 'Paolino', 'Paperopoli', 'A1010', '1001 32567')
GO
INSERT INTO [Tabella_1] ([Nome], [Cognome], [Città], [COD], [Telefono])
VALUES('Paperone', 'De Paperoni', 'Paperopoli', 'A1021', '1001 98752')
GO
INSERT INTO [Tabella_1] ([Nome], [Cognome], [Città], [COD], [Telefono])
VALUES('Topolino', 'Toponi', 'Topolinia', 'A1030', '1002 38988')
GO