Documente Academic
Documente Profesional
Documente Cultură
1
Majoritatea componentelor unei declaraţii SQL sunt insensibile la litere mari sau mici. O excepţie importantă de
la această regulă este faptul că datele caractere literale trebuiesc scrise exact cum apar în baza de date. De
exemplu dacă scriem numele unei persoane ‘MARIN’ şi apoi căutăm numele folosind ‘Marin’ articolul nu va fi
găsit.
Deşi SQL este de liber format, o declaraţie SQL sau un set de declaraţii este mult mai interesantă dacă este
folosită alinierea. De exemplu:
• Fiecare clauză din declaraţie ar trebui scrisă pe linie nouă.
• Începutul fiecărei clauze ar trebui scrisă sub începutul altei clauze.
• Dacă o clauză are mai multe părţi ele ar trebui să apară pe linii separate şi să fie inclusă la începutul
clauzei pentru a arăta relaţia dintre ele.
În acest capitol vom folosi următoarea modalitate pentru a defini declaraţiile SQL:
• Literele mari sunt folosite în reprezentarea cuvintelor rezervate şi trebuiesc scrise exact.
• Literele mici sunt folosite în reprezentarea cuvintelor definite de către utilizator.
• “|” indică o alegere între alternative; de exemplu a | b | c.
• Parantezele acolade indică un element dorit: de exemplu, {a}.
• Parantezele pătrate indică un element opţional: de exemplu, [a].
• Punctele (…) sunt folosite pentru a indica repetiţia opţională a unui element nul sau a unui alt
element de mai multe ori. De exemplu: {a|b}[,c…], ceea ce înseamnă a sau b urmat de zero sau mai
multe repetiţii al lui c separate prin virgulă.
În practică declaraţiile LDD sunt folosite pentru crearea de structuri de baze de date (tabele), iar declaraţiile
LMD pentru a popula şi interoga tabelele. În acest capitol vom prezenta declaraţiile LMD înaintea celor LDD
pentru a arăta importanţa relativă a declaraţiilor LMD.
Tabelul cadre_didactice:
nr_mat nume prenume funcţia vechime salariu
1111 Popa Ioan lect. 15 400,000
1112 Liana Carmen conf. 20 700,000
1113 Barbu Traian conf. 25 900,000
1114 Ştefan Elena conf. 25 900,000
1115 Savu Alexandru conf. 28 950,000
1116 Ionescu Mircea lect. 18 400,000
Tabelul secţii:
cod_sec denumire iniţiale
1 Matematică M
2 Informatică I
3 Matematică-fizică MF
4 Fizică-chimie FC
2
Tabelul grupe:
cod_sec cod_gr nr_semigrupe nr_studenţi
1 1 2 25
1 2 2 24
2 1 1 30
3 1 2 28
3 2 1 24
4 1 2 29
În această declaraţie expresie_coloană reprezintă o coloană sau o expresie; alias reprezintă o prescurtare a
numelui de tabel. Pentru cuvintele rezervate avem următoarea semnificaţie:
FROM specifică tabelul sau tabelele care vor fi folosite;
WHERE specifică liniile care trebuiesc recuperate cu ajutorul unor condiţii;
GROUP BY grupează toate liniile din tabele care au aceeaşi valoare pe coloana specificată;
HAVING selectează grupurile care respectă condiţia de căutare;
SELECT specifică coloanele care vor apărea în rezultatul interogării;
ORDER BY ordonează valorile returnate după coloanele specificate.
Ordinea clauzelor în declaraţia SELECT nu poate fi schimbată. Singurele două clauze obligatorii sunt primele
două: SELECT şi FROM celelalte fiind opţionale. Operaţia SELECT este închisă, rezultatul interogării unui
tabel fiind tot un tabel. Există mai multe variante ale acestei comenzi, totuşi exemplele care urmează ilustrează
principalele variante ale acestei declaraţii.
Interogări simple
salariu salariu
400,000 400,000
700,000 700,000
900,000 900,000
900,000 950,000
950,000
400,000
Clauza WHERE
Exemplele de mai sus arată folosirea declaraţiei SELECT pentru a recupera toate liniile dintr-un tabel. Totuşi,
deseori avem nevoie de a restrânge liniile care au fost recuperate. Acest lucru se poate realiza cu clauza WHERE
care conţine cuvântul cheie urmat de o condiţie de căutare care specifică liniile ce trebuiesc recuperate.
În SQL avem următoarii operatori de comparaţie: =, <, >, <=, >=, < >, != (diferit).
Multe predicate complexe pot fi generate folosind operatori logici AND, OR, şi NOT, cu paranteze sau nu,
pentru a arăta ordinea de valoare. Regulile pentru evaluarea expresiilor condiţionate sunt:
• O expresie evaluată de la stânga la dreapta.
• Subexpresiile în paranteze sunt evaluate prima dată.
• Operatorii NOT sunt evaluaţi înaintea operatorilor AND şi OR.
• Operatorii AND sunt evaluaţi înaintea celor OR.
Folosirea parantezelor este întotdeauna recomandată pentru a elimina posibilile ambiguităţi.
Cele 5 condiţii principale de căutare sunt următoarele:
1. Comparaţia. Compară valorile unei expresii cu valorile altei expresii:
4
nr_mat nume prenume salariu
1113 Barbu Traian 900,000
1114 Ştefan Elena 900,000
1115 Savu Alexandru 950,000
2. Şir. Testează dacă valoarea unei expresii este inclusă într-un şir de valori specificate
(BETWEEN/NOT BETWEEN):
3. Apartenenţa la o mulţime. Testează dacă valoarea unei expresii aparţine unui set de valori
(IN/NOT IN):
5. Nul. Testează dacă o coloană are o valoare nulă (necunoscută) (IS NULL/IS NOT NULL).
În general, liniile tabelului rezultat a unei interogari SQL nu sunt aranjate într-o anumită ordine. Totuşi, putem
sorta rezultatele unei interogări folosind clauza ORDER BY din declaraţia SELECT. Clauza ORDER BY
conţine o listă de identificatori de coloană pentru ca rezultatul să fie sortat şi separat prin virgulă. Identificatorul
de coloană poate fi, fie un nume de coloană, fie un număr de coloană care identifică un element din lista
SELECT dîndu-ne poziţia acestuia în listă:1 pentru primul element din listă, 2 pentru al doilea, ş.a.m.d.
Numerele de coloană pot fi folosite dacă coloana ce trebuie sortată este o expresie şi nici o clauză AS nu este
specificată în vederea ataşări unui nume pentru coloană, nume care ar putea fi de referinţă ulterior. Clauza
ORDER BY ne permite ordonarea articolelor recuperate în mod crescător (ASC) sau descrescător (DESC) pe
orice coloană sau combinaţie de coloane indiferent dacă coloana apare sau nu în rezultat.Totuşi, unele dialecte
5
insistă asupra faptului ca elementele ORDER BY să apara în lista SELECT. În ambele cazuri, clauza ORDER
BY trebuie să fie întotdeauna ultima în declaraţia SELECT.
Este posibil de a include mai multe elemente în clauza ORDER BY. Cheia de sortare majoră determină ordinea
generală a tabelului rezultat. Dacă cheia de sortare majoră este unică, nu mai este nevoie de nici o cheie de
control pentru sortare. Totuşi, dacă cheia de sortare majoră nu este unică, ar putea să existe mai multe linii din
tabelul rezultat cu aceeaşi valoare pentru cheia de sortare majoră. În acest caz, ar fi de dorit să se ordoneze liniile
cu aceeaşi valoare pentru cheia de sortare majoră cu ajutorul unei chei de sortare adiţională. Dacă apare un al
doilea element în clauza ORDER BY, atunci acesta se numeşte cheie de sortare minoră.
Standardul ISO specifică faptul că zerourile dintr-o coloană sau expresie sortată cu ORDER BY trebuiesc tratate
mai puţin sau mai mult decît toate valorile nenule. Acest lucru rămîne la alegerea implementorului SGBD.
6
SELECT nr_mat, COUNT(salariu)
FROM cadre_didactice;
deoarece lista SELECT conţine atât un nume de coloană (nr_mat) cât şi o funcţie complexă separată (COUNT),
fără a fi folosită o clauză GROUP BY.
Exemple:
1. Utilizarea funcţiei COUNT(*):
contor
4
contor
3
contor total_sal
4 4,450,000
Interogările sumare de mai sus sunt similare cu totalele de la sfârşitul raportului. Se condensează toate datele din
raport într-o singură linie sumară de date. Totuşi, este deseori folositor de a avea subtotale în raport. Pentru
aceasta putem folosi clauza GROUP BY din declaraţia SELECT. O interogare care cuprinde clauza GROUP BY
se numeşte interogare grupată, deoarece grupează datele din tabelele SELECT şi crează o singură linie pentru
fiecare grup. Coloanele numite în clauza GROUP BY se numesc coloane de grupare. Standardul ISO cere ca
clauzele SELECT şi GROUP BY să fie strâns integrate.Când se foloseşte GROUP BY, fiecare element din lista
SELECT trebuie să aibă valoare unică pe grup. În plus, clauza SELECT poate să conţină numai:
• nume de coloană,
• funcţii complexe,
• constante,
• o expresie cuprinzînd combinaţii ale elementelor de mai sus.
Toate numele de coloană din lista SELECT trebuie să apară în clauza GROUP BY, în afară de cazul când
numele este folosit numai într-o funcţie complexă. Reciproca nu este adevărată: pot să existe nume de coloane în
clauza GROUP BY care nu apar în lista SELECT. Când clauza WHERE este folosită cu GROUP BY, prima dată
este apelată clauza WHERE, apoi grupurile sunt formate din liniile rămase ceea ce satisface condiţia de căutare.
7
Standardul ISO consideră două zerouri ca fiind egale pentru scopurile clauzei GROUP BY. Dacă două
linii au zerouri în aceeaşi coloană de grupare şi valori identice în toate coloanele de grupare nenule, ele sunt
combinate în acelaşi grup.
Exemplu:
SELECT funcţia, COUNT(nr_mat) AS contor, SUM(salariu) AS total_sal
FROM cadre_didactice
GROUP BY funcţia
ORDER BY funcţia;
Clauza HAVING este folosită împreună cu clauza GROUP BY pentru a restrânge grupurile care apar la finalul
tabelului rezultat. Deşi sunt similare în sintaxă, HAVING şi WHERE servesc scopuri diferite. Clauza WHERE
strecoară linii individuale în finalul tabelului rezultat, iar HAVING strecoară grupuri în finalul tabelului rezultat.
Standardul ISO cere ca numele coloană folosite în clauza HAVING să apară, deasemenea, în lista GROUP BY
sau să fie conţinute într-o funcţie complexă. În practică, condiţia de căutare din clauza HAVING include
întotdeauna cel puţin o funcţie complexă, altfel condiţia de căutare ar putea fi mutată în clauza WHERE şi
aplicată pe linii individuale.
Clauza HAVING nu este parte importantă a SQL, orice interogare exprimată folosind clauza HAVING poate fi
rescrisă întotdeauna fără clauza HAVING.
Exemplu:
SELECT funcţia, COUNT(nr_mat) AS contor, SUM(salariu) AS total_sal
FROM cadre_didactice
GROUP BY funcţia
HAVING COUNT(nr_mat)>2
ORDER BY funcţia;
Subinterogări
Unele declaraţii SQL pot avea o declaraţie SELECT completă încrustată în interiorul lor. Rezultatele acestei
declaraţii SELECT interioare (sau subselect) sunt folosite în declaraţiile exterioare pentru a ajuta la determinarea
conţinutului rezultatului final. Un subselect poate fi folosit în clauzele WHERE şi HAVING a unei declaraţii
SELECT exterioare, unde acesta este numit subinterogare sau interogare intercalată. Subselectele pot apărea, de
asemenea, în declaraţiile INSERT, UPDATE şi DELETE.
Exemplu:
SELECT cod_gr, nr_semigrupe, nr_studenţi
FROM grupe
WHERE cod_sec =
(SELECT cod_sec
FROM secţii
WHERE denumire = ‘Matematica’);
Subinterogarea poate fi privită ca producătorul unor tabele temporare de rezultate, care pot fi accesate şi folosite
de către declaraţii exterioare. O subinterogare poate fi folosită imediat după un operator relaţional (=,< , >, <=,
>=, < >) într-o clauză WHERE sau HAVING. Subinterogarea însăşi este întodeauna închisă între paranteze.
Asupra subinterogărilor se aplică următoarele reguli:
1) Clauza ORDER BY nu poate fi folosită într-o subinterogare (deşi ea poate fi folosită în
majoritatea declaraţiilor SELECT exterioare.
2) Lista subinterogărilor SELECT trebuie să conţină un singur nume coloană sau o singură expresie,
excepţie făcînd subinerogările care folosesc cuvântul cheie EXISTS.
3) Deoarece lipsesc, numele coloană dintr-o subinterogare se referă la numele tabel din clauza
FROM a subinterogării. Este posibil să se recurgă la un tabel dintr-o clauză FROM a unei interogări exterioare în
modificarea numelui coloană.
4) Când o subinterogare este una din cei doi operanţi implicaţi într-o comparaţie, subinterogarea
trebuie să apară în partea dreaptă a comparaţiei.
5) O subinterogare nu poate fi folosită ca operant într-o expresie.
Cuvintele ANY şi ALL pot fi folosite cu subinterogări care produc o singură coloană a numerelor. Dacă
subinterogarea este precedată de cuvântul cheie ALL, condiţia va fi adevărată numai dacă este satisfăcută de
toate valorile date de subinterogare. Dacă subinterogarea este precedată de cuvântul cheie ANY, condiţia va fi
adevărată dacă este satisfăcută de orice (una sau mai multe) valoare dată de subinterogare. Dacă subinterogarea
este vidă, condiţia ALL returnează valoarea adevărat, iar condiţia ANY returnează valoarea fals. Standardul ISO
permite folosirea calificativului SOME în locul lui ANY.
Exemple:
1. Utilizarea cuvântului rezervat ANY:
SELECT nume, prenume, salariu
FROM cadre_didactice
WHERE salariu > ANY
(SELECT salariu
FROM cadre_didactice
WHERE funcţia =’conf’);
Interogări multi-tabele
Toate exemplele considerate pînă acum au o limitare majoră: toate coloanele ce trebuie să apară în tabelele
rezultat trebuie să provină dintr-un singur tabel. În multe cazuri, acest lucru nu este suficient. Pentru a combina
coloanele din mai multe tabele în obţinerea unui tabel rezultat, avem nevoie de o operaţie de joncţiune. Operaţia
de joncţiune SQL combină informaţia din două tabele formînd perechi de linii înrudite din cele două tabele.
Perechile de linii ce alcătuiesc tabelul asociat sunt toate acolo unde coloanele corespunzătoare din cele două
tabele au aceeaşi valoare.
Dacă avem nevoie să obţinem informaţii din mai multe tabele, putem alege între folosirea unei subinterogări şi a
unei joncţiuni. Dacă tabelul rezultat final trebuie să conţină coloane din diferite tabele, atunci trebuie să folosim
joncţiunea. Pentru a reuşi operaţia de joncţiune, trebuie doar să includem mai multe nume de tabele în clauza
FROM, folosind ca separator virgula şi incuzînd clauza WHERE pentru a specifica coloanele joncţiunii. De
asemenea, este posibil să folosim alias pentru un tabel specificat în clauza FROM. În acest caz, aliasul este
9
separat de numele tabelului printr-un spaţiu. Un alias poate fi folosit pentru a modifica numele coloană ori de
câte ori există ambiguităţi privind sursa numelui coloană. De asemenea, se mai poate folosi ca o notaţie pentru
numele tabelului. Dacă un alias este specificat, trebuie folosit oriunde numele tabelului ar putea fi specificat.
Joncţiunea este o submulţime a unei combinaţii mult mai generale a două tabele cunoscute cum ar fi produsul
cartezian a două tabele. Produsul cartezian a doua tabele este un alt tabel alcătuit din toate perechile posibile de
linii din cele doua tabele. Coloanele tabelului produs sunt toate coloanele primului tabel urmat de toate coloanele
celui de al doilea tabel. Dacă specificăm o interogare doi-tabel fără clauza WHERE, SQL produce produsul
cartezian al celor două tabele ca fiind interogarea rezultat.
Procedura pentru generarea rezultatelor unui SELECT cu o asociere este:
1. Se formează produsul cartezian a tabelelor numite în clauza FROM.
2. Dacă există o clauză WHERE, se aplică condiţia de căutare fiecărei linii a tabelului produs, reţinînd
acele linii care satisfac condiţia. În termenii algebrei relaţionale, această operaţie produce o restricţie
a produsului cartezian.
3. Pentru fiecare linie rămasă, se determină valoarea fiecărui element din lista SELECT în scopul
producerii unei singure linii în tabelul rezultat.
4. Dacă SELECT DISTiNCT a fost specificat, se elimină orice linie dublă din tabelul rezultat. În
algebra relaţională, pasul 3 şi 4 sunt echivalente cu o proiecţie a restricţiei asupra coloanelor
menţionate în lista SELECT.
5. Dacă există o clauza ORDER BY, se sortează în modul cerut tabelul rezultat.
Exemple:
Cele mai comune interogări muti-tabel implică două tabele care au o relaţie 1:M (sau tată/fiu). Interogarea
precedentă este o astfel de interogare. Fiecare fiu are un tată asociat şi fiecare părinte are asociaţi mai multi fii.
Perechile de linii care generează interogarea rezultat sunt combinaţii de linii tată/fiu. Tabelul care conţine cheia
străină este un tabel fiu, iar tabelul care conţine cheia fundamentală este un tabel tată. Pentru a folosi relaţia
tată/fiu într-o interogare SQL, vom specifica o condiţie de căutare care compară cheia străină cu cheia
fundamentală. În exemplul de mai sus se face o astfel de comparaţie.
Standardul SQL2 furnizează următoarele moduri alternative pentru a specifica această asociere:
FROM secţii s JOIN grupe g ON s.cod_sec=g.cod_sec
FROM secţii JOIN grupe USING cod_sec
FROM secţii NATURAL JOIN grupe
În fiecare caz, clauza FROM înlocuieşte clauzele originale FROM şi WHERE.
Joncţiuni externe
Operaţia de joncţiune combină datele din două tabele formînd perechi de linii specificate, unde coloanele
corespunzătoare din fiecare tabel au aceeaşi valoare. Dacă o linie a tabelului este fără pereche, linia este omisă
din tabelul rezultat. Acesta a fost cazul pentru joncţiunile examinate mai sus. Standardul ISO furnizează un alt
set de operatori de joncţiune numiţi joncţiuni externe. Joncţiunea externă reţine liniile care nu satisfac condiţia de
joncţiune.
Există trei tipuri de joncţiuni externe:
1. joncţiune externă stângă:
SELECT o.*, m.*
FROM oraşe o LEFT JOIN municipii m
ON o.denumire = m.denum_m;
10
2. joncţiune externă dreaptă:
SELECT o.*, m.*
FROM oraşe o RIGHT JOIN municipii m
ON o.denumire = m.denum_m;
Cuvintele cheie EXISTS şi NOT EXISTS se folosesc numai cu subinterogări. Ele produc un rezultat simplu
adevărat/fals. EXISTS este adevărat dacă şi numai dacă există cel puţin o linie în tabelul rezultat returnată de
către interogare şi este falsă dacă subinterogarea returnează un tabel rezultat vid. NOT EXISTS este opusul lui
EXISTS. În timp ce EXISTS şi NOT EXISTS verifică numai existenţa sau inexistenţa liniilor în tabelul rezultat
al subinterogării, subinterogarea poate conţine orice număr de coloane. Pentru simplificare, subinterogarea
urmînd una din aceste cuvinte cheie este de obicei de forma: (SELECT*…).
Exemplu:
SELECT cod_gr, nr_semigrupe, nr_studenţi
FROM grupe g
WHERE EXISTS
(SELECT *
FROM secţii s
WHERE g.cod_sec = s.cod_sec AND iniţiale=’M’ );
În SQL, putem folosi operaţiile normale cu mulţimi: reuniune, intersecţia şi diferenţa, pentru a combina
rezultatele a două sau mai multe interogări într-un singur tabel rezultat. Reuniunea a două tabele, A şi B, este un
tabel ce conţine toate liniile care sunt atât în tabelul A cât şi în B. Intersecţia a două tabele, A şi B este un tabel
ce conţine toate liniile comune celor două tabele. Diferenţa a două tabele, A şi B, este un tabel ce conţine toate
liniile care sunt în A, dar nu sunt în B.
Există restricţii asupra tabelelor care pot fi combinate folosind operaţiile cu mulţimi. Cea mai importantă
restricţie este că cele două tabele sunt compatibile (prin asociere), adică ele au aceaşi structură. Aceasta implică
faptul că cele două tabele trebuie să conţină acelaşi numar de coloane şi că, coloanele lor corespunzătoare să aibă
aceleaşi tipuri şi lungimi de date. Este responsabilitatea utilizatorului de a se asigura că valorile datelor în
coloanele corespunzătoare provin din acelaşi domeniu. De exemplu, ar fi fără sens să combinăm o coloană care
conţine vârsta personalului cu numărul camerelor dintr-o proprietate, chiar dacă ambele coloane ar putea avea
acelaşi tip de dată: de exemplu, SMALLINT.
Cei trei operatori de mulţimi sunt numiţi, în standardul ISO, UNION, INTERSECT şi EXCEPT. Formatul
clauzei operatorului de mulţimi este, în fiecare caz:
operator [ALL][CORRESPONDING [BY {coloană [,…]}]]
Dacă CORRESPONDING BY este specificat, atunci operaţia cu mulţimi este realizată prin coloana (coloanele)
specificate. Dacă CORRESPONDING este specificat dar fără clauza BY, operaţia cu mulţimi este realizată prin
coloanele care sunt comune ambelor tabele. Dacă ALL este specificat, rezultatul poate include linii duble.
11
Unele dialecte ale SQL nu acceptă INTERSECT şi EXCEPT, altele folosesc MINUS în locul lui EXCEPT.
Exemple:
1. Utilizarea operatorului UNION:
(SELECT denumire AS oraşe
FROM oraşe
WHERE denumire IS NOT NULL)
UNION
(SELECT denum_m AS oraşe
FROM municipii
WHERE denum_m IS NOT NULL)
oraşe
Braşov
Codlea
Timişoara
Iaşi
oraşe
Braşov
Timişoara
3. Utilizarea operatorului EXEPT:
oraşe
Codlea
Există două forme a declaraţiei INSERT. Prima formă permite inserarea unei singure linii într-un tabel
specificat. Formatul declaraţiei INSERT este:
nume_tabel poate fi un tabel de bază sau un view actualizabil şi lista_coloană reprezintă o listă a unuia sau mai
multor nume coloane separate prin virgulă. Lista _coloană este opţională, dacă este omisă, SQL presupune o
listă a tuturor coloanelor în ordinea lor originală din CREATE TABLE. Dacă este specificată, atunci orice
coloană care este omisă din listă trebuie să fie declarată ca şi coloană NULL cănd tabelul a fost creat, în cazul în
12
care opţiunea DEFAULT nu a fost folosită când s-a creat coloana. Lista_valoare_dată trebuie să se potrivească
cu lista coloană după cum urmează :
• Numărul elementelor din ambele liste trebuie să fie acelaşi
• Trebuie să fie o corespondentă directă între poziţia elementelor din ambele liste, astfel încât primul
element din lista_valoare_dată corespunde primului element din lista_coloană, al doilea element din
lista_valoare_dată corespunde celui de-al doilea element din lista_coloană, ş.a.m.d.
• Tipul datei fiecărui element din lista_valoare_dată trebuie să fie compatibil cu tipul datei coloanei
corespunzătoare.
Exemplu:
A doua formă a declaraţiei INSERT permite copierea mai multor linii din una sau mai multe tabele în altele.
Formatul este:
Nume_tabel şi lista_coloană sunt definite ca mai sus în cazul încasării unei singure linii. Clauza SELECT poate
fi orice declaraţie valabilă SELECT. Liniile inserate în tabelul specificat sunt identice cu cele din tabelul rezultat
produs de subselect. Aceleaşi restricţii aplicate primei forme a declaraţiei INSERT se aplică şi aici.
Exemplu:
INSERT INTO oraşe
(SELECT cod_m, denum_m
FROM municipii);
Declaraţia UPDATE permite schimbarea conţinutului liniilor existente dintr-un tabel specificat. Formatul
comenzii este:
UPDATE nume_tabel
SET nume_coloană 1=valoare_dată 1[, nume_coloană 2= valoare_dată 2…]
[WHERE condiţie_căutare]
Nume_tabel poate fi numele unui tabel de bază sau un view actualizabil. Clauza SET specifică numele unei sau
mai multor coloane care urmează să fie actualizate. Clauza WHERE este opţională. Dacă este omisă, coloana
specificată este actualizată pentru toate liniile din tabel. Dacă clauza WHERE este specificată, numai acele linii
care satisfac condiţia_căutare sunt actualizate. Noile valoare_dată trebuie să fie compatibile cu tipul de dată
pentru coloana corespunzătoare.
Exemplu:
UPDATE cadre_didactice
SET funcţia =’conf.’
WHERE funcţia=’lect.’;
Ştergerea datei din baza de date (DELETE)
Declaraţia DELETE permite ştergerea liniilor dintr-un tabel specificat. Formatul comenzii este:
13
Limbajul de definire a datei SQL (LDD) ne permite crearea şi distrugerea obiectelor bază de dată (scheme,
domenii, tabele, view-uri, rapoarte şi indexuri). În această secţiune, examinăm, pe scurt, cum să creăm şi să
distrugem scheme, tabele şi indexuri.
Principalele declaraţii de definirii datei în SQL sunt:
CREATE SCHEMA DROP SCHEMA
CREATE DOMAIN ALTER DOMAIN DROP DOMAIN
CREATE TABLE ALTER TABLE DROP TABLE
CREATE VIEW DROP VIEW
Deasemenea, următoarele două declaraţii au fost prevăzute de multe SGBD:
CREATE INDEX DROP INDEX
Aceste declaraţii sunt folosite pentru a crea, schimba sau distruge structurile care alcătuiesc schema conceptuală.
Înainte de a considera declaraţiile LDD, discutăm sintaxa identificatorilor SQL şi tipurile de date SQL care pot fi
folosite în definirea coloanelor tabel.
Uneori pentru scopuri de manipulare şi conversie, tipurile de date caracter şi bit sunt atribuite tipurilor de date
string, şi exact numeric şi aproximativ numerice sunt atribuite tipurilor de date numeric, deoarece ele împart
proprietăţisimilare.
Datele caracter
Datele caracter conţin o secvenţă de caractere dintr-un set de caractere definite de implementator, adică este
definită de către distribuitorul dialectului particular SQL. Astfel, caracterele exacte care pot apărea ca valorile
datelor într-o coloană tip caracter vor varia. ASCII este una din seturile utilizate în comun astăzi. Formatul
pentru specificarea unui tip de dată caracter este:
CHARACTER [VARYING][length]
CHARACTER can be abbreviated to CHAR and
CHARACTER VARYING to VARCHAR.
Când o coloană caracter string este definită, o lungime poate fi specificată să indice maximul numărului de
caractere conţinute în coloane (lungimiea implicită este 1). Un caracter string poate fi definită ca avînd o
lungime fixă sau variabilă. Dacă stringul este definit cu lungime fixă, şi dacă introducem un string cu câteva
caractere mai puţin decât această lungime, stringul este completat cu spaţii la dreapta pentru a obţine lungimea
cerută. Dacă stringul este definit cu lungime variabilă şi introducem un string cu câteva caractere mai puţin decât
această lungime, numai acele caractere introduse sunt rezervate, astfel folosindu-se mai puţine spaţii. De
14
exemplu, numărul matricol din coloana nr_mat a tabelului cadre_didactice, care are o lungime fixă de 4
caractere, este declarat ca:
nr_mat CHAR(4)
Coloana nume a tabelului cadre_didactice, care are un număr variabil de caractere până la maximum de 20, este
declarată ca:
nume VARCHAR(20)
Datele bit
Tipul de date bit este folosit pentru definirea stringurile bit, adică o secvenţă de cifre binare, fiecare avînd sau
valoarea 0 sau 1. Formatul pentru specificarea tipului de dată bit este similar cu cel al tipului de dată caracter:
BIT [VARYING][lenght]
De exemplu, pentru a ţine lungimea fixă a stringului binar ‘0011’, declarăm o coloană bit_string, ca:
bit_string BIT(4)
Tipul de dată exact numeric este folosit pentru definirea numerelor cu reprezentare exactă. Numărul conţine
cifre, un punct zecimal opţional şi un semn opţional. Un tip de dată exact numeric conţine o precizie şi o scală.
Precizia dă numărul total a cifrelor zecimale semnificative: adică numărul total al cifrelor, incluzînd zecimalele
dar excluzînd punctul. Scala dă numărul total al zecimalelor. De exemplu, valoarea exact numerică -12.345 are
precizia 5 şi scala 3. Un caz special survine în cazul datelor exact numerice întregi. Există mai multe moduri de a
specifica un tip de dată exact numeric:
Tipul de dată aproximativ numeric este folosit pentru definirea numerelor care nu au o reprezentare exactă, ca de
pildă numerele reale. Aproximativ numeric, sau punct float, este similar notaţiei stiinţifice în care un număr este
scris ca o putere de zece. De exemplu, 10E3, +5.2E6, -0.2E-4. Există mai multe moduri de a specifica un tip de
dată aproximativ numeric:
FLOAT [precision]
REAL
DOUBLE PRECISION
Datele dată-timp
Acest tip de dată este folosit pentru a defini puncte în timp la un anumit grad de precizie. Ca exemple putem da
date calendaristice, intervale de timp şi intervale ale unei zile. Standardul ISO foloseşte pentru acest tip de dată
cuvintele rezervate: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, TIMEZONE_HOUR şi
TIMEZONE_MINUTE. Ultimele două câmpuri specifică ora şi minutul pentru anumite zone geografice.
Trei tipuri ale acestui tip de date sunt acceptate:
DATE
TIME [time_precision][WITH TIME ZONE]
15
TIMESTAMP [time_precision][ WITH TIME ZONE]
DATE este folosit pentru a reprezenta datele calendaristice folosind cuvintele rezervate YEAR, MONTH şi
DAY.
TIME este folosit pentru a reprezenta timpul folosind cuvintele rezervate HOUR, MINUTE şi SECOND.
TIMESTAMP reprezintă datele calendaristice şi timpul.
Time_precision reprezintă unitatea de măsură a câmpului SECOND. Dacă nu este specificat acesta este implicit
0 în TIME fiind vorba de secunde, iar în TIMESTAMP valoarea implicită este 6 fiind vorba de microsecunde.
Cuvântul cheie WITH TIME ZONE controlează prezenţa câmpurilor TIMEZONE_HOUR şi
TIMEZONE_MINUTE.
Date interval
Tipul de dată interval este folosit pentru a reprezenta intervale de timp. Fiecare tip de dată interval este alcătuit
dintr-un subset învecinat al câmpurilor: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND. Există două clase
de date interval: intervale an-lună şi intervale zi-timp. Clasa an-lună poate conţine numai câmpurile YEAR şi/sau
MONTH, iar clasa zi-timp poate conţine o selecţie invecinată din DAY, HOUR, MINUTE, SECOND.
Formatul pentru specificarea tipului da dată interval este:
De aceea, dacă creatorul unei scheme “sql-schemă” este Ionescu, declaraţia SQL este:
O schemă poate fi distrusă folosind declaraţia DROP SCHEMA, care are forma următoare:
Dacă RESTRICT este specificat, care este şi valoarea implicită dacă nici unul din calificative nu este specificat,
schema trebuie să fie vidă sau operaţia eşuează. Dacă CASCADE este specificat, operaţia aranjează în cascadă
toată obiectele asociate schemei în ordinea definită înainte.
16
În prezent declaraţiile CREATE şi DROP SCHEMA nu sunt încă larg implementate. În unele implementări, în
locul declaraţiei CREATE SCHEMA este folosită declaraţia următoare:
Avînd creată structura bazei de dată, putem acum crea structurile tabelelor de bază a relaţiilor pentru a fi
localizate în baza de date. Crearea unui tabel se face folosind comanda CREATE TABLE, care are următoarea
sintaxă principală:
CREATE TABLE nume_tabel
(nume_coloană tip_dată [NULL | NOT NULL][,…])
Această comandă crează un tabel numit nume_tabel alcătuit din una sau mai multe coloane al câmpului tip_dată
specificat. Specificatorul NULL este folosit pentru a indica dacă unei coloane îi este permis sau nu să conţină
null-uri. Un null este diferit de spaţiu sau 0 şi este folosit pentru a reprezenta date dacă acestea nu sunt
disponibile, pierdute sau nu sunt aplicabile. Când NOT NULL este specificat, sistemul respinge orice încercare
de inserare a unui null în coloane. Dacă NULL este specificat, sistemul acceptă null-uri. Valoarea implicită ISO
este NULL. De exemplu, pentru crearea tabelului cadre_didactice avem:
Cu timpul structura unei baze de date se va schimba, tabele noi fiind create iar altele vechi nu vor mai fi
necesare. Putem şterge un tabel suplimentar din baza de date folosind declaraţia DROP TABLE, care are
formatul:
Observăm că această comandă şterge nu numai tabelul specificat, ci şi toate liniile din interiorul acesteia. Dacă
se doreşte ştergerea liniilor din tabel dar să se reţină structura tabelului trebuie folosită declaraţia DELETE.
Dacă RESTRICT este specificat în comanda DROP TABLE şi există orice alte obiecte a căror existenţă depinde
de existenţa tabelului, asupra căruia acţionează comanda, SQL nu permite comenzii DROP TABLE să continue.
Dacă CASCADE este specificat SQL automat şterge toate obiectele dependente de tabel (şi obiectele dependente
de aceste obiecte).
O folosire uzuală a comenzii DROP TABLE este de a corecta greşelile făcute la crearea unui tabel. Dacă este
creat un tabel cu o structură incorectă se poate folosi DROP TABLE pentru a şterge tabelul nou creat şi începe
din nou.
Standardul ISO furnizează declaraţia ALTER TABLE pentru modificarea structurii unui tabel odată ce a fost
creat. Definirea declaraţiei ALTER TABLE în standardul ISO este alcătuită din 6 opţiuni pentru:
• a adăuga o nouă coloană la un tabel;
• a şterge o coloană dintr-un tabel ;
• a adăuga o nouă restricţie pentru tabel;
• a şterge o restricţie a tabelului;
• a stabilii o valoare implicită pentru o coloană;
• a şterge o valoare implicită a coloanei.
17
ALTER TABLE nume_tabel
[ADD [COLUMN] nume_coloană tip_dată [NOT NULL][UNIQUE]
[DEFAULT opţiune_implicită][CHECK(condiţie_căutare)]]
[DROP [COLUMN] nume_coloană [RESTRICT | CASCADE]]
[ADD [CONSTRAINT [nume_restricţie]] definiţie_restricţie_tabel]
[DROP CONSTRAINT nume_restricţie [RESTRICT | CASCADE]]
[ALTER [COLUMN] SET DEFAULT opţiune_implicită]
[ALTER [COLUMN] DROP DEFAULT]
unde parametrii sunt definiţi ca şi în declaraţia CREATE TABLE. Definiţie_restricţie_tabel este una din
clauzele: PRIMARY KEY, UNIQUE, FOREIGN KEY sau CHECK. Clauza ADD COLUMN este similară cu
definirea unei coloane din declaraţia CREATE TABLE. Clauza DROP COLUMN specifică numele coloanei ce
trebuie ştearsă din definiţia tabelului. Această clauză are un calificativ opţional care ne permite să specificăm
dacă acţiunea DROP este în cascadă sau nu. Avem acelaş concept ca şi la calificativul RESTRICT | CASCADE
a declaraţiei DROP TABLE.
De exemplu pentru a adăuga coloana “vechime” la tabelul cadre_didactice folosim comanda:
ALTER TABLE cadre_didactice
ADD vechime INTEGER(2);
Declaraţia ALTER TABLE nu este disponibilă în toate dialectele SQL. În unele dialecte, declaraţia nu poate fi
folosită pentru a muta o coloană existentă dintr-un tabel.
Un index este o structură care furnizează accesul rapid la liniile unui tabel bazat pe valorile uneia sau mai multor
coloane. Prezenţa unui index poate îmbunătăţi simţitor performanţa unei interogări. Indexurile sunt create, de
obicei, pentru a satisface criteriul de căutare particular după ce tabelul a fost folosit un timp şi a crescut în
mărime. Crearea indexurilor nu este standardizată în SQL. Totuşi multe dialecte acceptă cel puţin următoarea
formă a acestei comenzi:
Coloanele specificate alcătuiesc cheia index şi ar trebui listate în ordine descrescătoare. Indexurile pot fi create
numai în tabele de bază nu şi în view-uri. Dacă clauza UNIQUE este folosită, unicitatea coloanei sau combinaţiei
de coloane indexate va fi decretată de către sistem. Deşi indexurile pot fi create oricând, putem avea probleme
dacă încercăm să creăm un index unic pe un tabel care conţine articole, deoarece valorile provenite din coloana
(coloanele) indexată poate să conţină deja dubluri. De aceea este mai bine să creăm indexuri unice, cel puţin
pentru coloane cheie principale, atunci când tabelul de bază este creat şi sistemul nu va asigura automat
unicitatea cheii principale.
Pentru tabelul cadre_didactice putem crea următoarele indexuri:
Pentru fiecare coloană putem specifica dacă ordinea este ascendentă (ASC) sau descendentă (DESC), valoarea
implicită fiind ASC.
Dacă creăm un index pentru un tabel de bază şi mai târziu decidem că nu mai este necesar, declaraţia DROP
INDEX şterge indexul din baza de date. DROP INDEX are formatul:
DROP INDEX nume_index
Declaraţia următoare va şterge indexul creat în exemplul anterior:
DROP INDEX matricol_ind;
18
1.4.1. Crearea unui view (CREATE VIEW)
Formatul declaraţiei CREATE VIEW este:
Se poate repartiza, opţional, un nume pentru fiecare coloană din view. Dacă o listă a numelor de coloană este
specificată, atunci trebuie să aibă acelaşi număr de elemente ca şi numărul coloanelor produse de către subselect.
Dacă lista numelor de coloană este omisă, fiecare coloană din view ia numele coloanei corespunzătoare din
subselect. Lista numelor de coloană trebuie să fie specificată în cazul în care există orice ambiguitate în numele
unei coloane. Aceasta se poate întâmpla dacă subselectul include coloane calculate şi subclauza AS nu a fost
folosită pentru a numi astfel de coloane sau produce două coloane cu nume identice ca rezultat a unei joncţiuni.
Subselectul este cunoscut ca interogare definită. Dacă WITH CHECK OPTION este specificat, SQL asigură
faptul că dacă o linie nu ajută la satisfacerea clauzei WHERE a interogării definite a view-ului, aceasta nu este
adăugată la tabelul view-ului.
Deşi toate view-urile sunt create în acelaşi mod, în practică diferite tipuri de view-uri sunt folosite pentru diferite
scopuri:
1. Wiew orizontal, care pemite restricţionarea accesului utilizatorilor la anumite linii ale unui tabel:
2. View vertical care pemite restricţionarea accesului utilizatorilor la anumite coloane ale unui tabel ale unui
tabel:
secţia grupa
Matematică 1
Matematică 2
Informatică 1
Matematică-fizică 1
Matematică-fizică 2
Fizică-chimie 1
19
1.4.2. Ştergerea unui view (DROP VIEW)
Un view este şters din baza de date cu declaraţia:
Dacă CASCADE este specificat, DROP VIEW şterge toate obiectele dependente, cu alte cuvinte, şterge toate
obiectele de referinţă ale view-ului. Dacă RESTRICT este specificat şi există orice alte obiecte a căror existenţă
depinde de existenţa view-ului ce urmează a fi şters, comanda este respinsă. Valoarea imlicită este RESTRICT.
De exemplu, putem şterge view-ul vechime_cadre folosind declaraţia:
DROP VIEW vechime_cadre;
Avantaje.
1. Independenţa datei
Un view poate prezenta o imagine consistentă, nemodificabilă a structurii bazei de date, chiar dacă tabelele sursă
principale sunt schimbate (de exemplu, coloane adăugate sau şterse, relaţii schimbate, tabele dezbinate,
restructurate sau redenumite). Dacă coloanele sunt adăugate sau şterse dintr-un tabel şi aceste coloane nu sunt
cerute de către view, atunci definirea view-ului nu necesită schimbări. Dacă un tabel existent este rearanjat sau
dezbinat, un view poate fi definit astfel încât utilizatorul poate continua să vadă vechiul tabel. În cazul dezbinării
unui tabel, vechiul tabel poate fi recreat prin definirea unui view joncţionînd noile tabele.
2. Universalitatea
Schimbările oricăror tabele în interogarea definită sunt imediat reflectate în view.
3. Securitatea
20
Fiecare utilizator poate avea privilegiul de a accesa baze de date numai printr-un mic set de view-uri, care
conţine date potrivite acelui utilizator, astfel restrângînd şi controlînd accesul la baza de date a fiecărui utilizator.
4. Complexitatea redusă
Un view poate simplifica interogările prezentarea datelor din mai multe tabele într-un singur tabel şi, astfel,
transformînd interogări multi-tabel în interogări 1-tabel.
5. Selectabilitatea
View-urile furnizează posibilitatea ca aceleaşi tabele principale să poată fi văzute de diferiţi utilizatori, în diferite
moduri.
6. Integritatea datei
Dacă WITH CHECK OPTION a declaraţiei CREATE VIEW este folosit, SQL asigură faptul că nici o linie care
nu satisface clauza WHERE a interogării definite nu este niciodată adăugată la orice tabel principal prin view,
prin aceasta asigurînd integritatea view-ului.
Dezavantaje.
Deşi view-urile furnizează multe beneficii semnificative, există de asemenea, câteva dezavantaje ale view-urilor
SQL:
1. Restricţia actualizării
În unele cazuri un view nu poate fi actualizat.
2. Restricţia structurii
Structura unui view este determinată la timpil creării lui. Dacă interogarea definită a fost de forma SELECT *
FROM …, atunci * se referă la coloanele tabelului de bază existent când a fost creat view-ul. Dacă coloanele
sunt ulterior adăugate la tabelul de bază, atunci aceste coloane nu vor apărea în view, în afară de cazul când
view-ul este şters şi recreat.
3. Performanţa
Există un neajuns care apare când folosim un view. În unele cazuri acest lucru va fi neglijabil; în alte cazuri
poate fi mai problematic. De exemplu, un view definit printr-o interogare complexă multi-tabel poate lua un timp
îndelungat pentru a fi prelucrat pe când rezoluţia view-ului trebuie să joncţioneze tabelele de fiecare dată când
view-ul este accesat. Rezoluţia view-ului cere resurse în plus calculatorului.
21