Sunteți pe pagina 1din 70

Baze de date

Limbajul SQL
3.1 Caracteristici generale ale SQL
SQL (Structured Query Language) este unul dintre cele mai puternice i larg
rspndite limbaje folosite pentru definirea i accesarea bazelor de date
relaionale. SQL nu se ncadreaz n categoria limbajelor de programare, fiind un
limbaj de aplicaii, destinat bazelor de date relaionale. SQL permite consultarea
unei bazei de date, sau executarea anumitor instruciuni asupra acesteia, prin
simpla specificare a informaiilor dorite sau a comenzilor de executat, fr fi
necesar indicarea modalitii concrete sau a algoritmilor de obinere a
rezultatului. Cu alte cuvinte, SQL poate fi considerat un limbaj declarativ
(neprocedural).
Dei este perceput drept facil i poate fi nsuit cu uurin de utilizatorii bazelor
de date, SQL permite totodat soluionarea rapid a unor solicitri complexe, ceea
ce explic interesul considerabil pe care limbajul l-a suscitat n rndul
productorilor de software. SQL este suportat de diferite sisteme de gestiune a
bazelor de date (Access i SQL Server (Microsoft), DB2 i Informix (IBM),
Oracle, Sybase etc.), limbajul dispunnd de mai multe dialecte, determinate de
specificul fiecrui S.G.B.D. n acelai timp, exist i versiuni standard, care se
bucur de o recunoatere universal n domeniul bazelor de date.
n prezent, rezolvarea problemelor de compatibilitate i portabilitate a codului
SQL se bazeaz pe standardele American National Standards Institute: ANSI
SQL-89, ANSI SQL-92 i ANSI SQL-99 (cunoscut i ca ANSI SQL3);
diferenele dintre acestea se manifest n planul regulilor de sintax, al cuvintelor
rezervate, caracterelor speciale i tipurilor de date.
Pentru fiecare standard ANSI SQL sunt definite subnivele, n raport cu care se
poate aprecia gradul n care un S.G.B.D. se conformeaz standardului respectiv:
nivelul 1 (entry level) - conformitate minimal;

nivelul 2 (intermediate level) - conformitate medie;

nivelul 3 (full level) - conformitate integral.


Dup cum se arat n documentaia Microsoft, n mod implicit, S.G.B.D-ul Access
implementeaz nivelul 1 al ANSI SQL-89, ns se poate opta i pentru sintaxa
ANSI SQL-92, care permite mai mult flexibilitate n definirea interogrilor i, n
acelai timp, o mai bun portabilitate a codului SQL ntre S.G.B.D. uri diferite.
Prezena calificativului structurat n denumirea limbajului se justific prin faptul
c orice cerere SQL definit asupra unei baze de date trebuie s respecte un
formalism specific, care const ntr-un anumit vocabular i un set de reguli de
sintax ce prescriu maniera de utilizare a elementelor de vocabular.

Limbajul SQL

Vocabularul SQL include o serie de cuvinte cheie, care pot fi ncadrate n


urmtoarele categorii:

Instruciuni - Determin executarea unei anumite aciuni. Exemple: CREATE


TABLE (crearea unui nou tabel), ALTER TABLE (modificarea structurii unui
tabel), SELECT (afiarea anumitor date din tabele), DELETE (tergerea
tuplurilor dintr-un tabel) etc.

Clauze - Permit specificarea unor argumente care nuaneaz instruciunile,


delimitnd entitile participante la interogare. Exemple: FROM (indic
tabelele-surse de date ale unei interogri), WHERE (specific restricii ce
limiteaz numrul nregistrrilor returnate de o interogare), ORDER BY
(furnizeaz criteriile folosite la sortarea rezultatelor unei interogri) etc.

Funcii - n raport cu specificul lor, efectueaz prelucrri asupra anumitor date


(desemnate drept parametrii, sau argumente ale funciei), rezultatele returnate
fiind valorificate n cadrul unor clauze SQL. ntruct nu urmrim prezentarea
exhaustiv a funciilor, ci delimitarea acestora ca elemente de sintax SQL,
vom trece n revist doar cteva funcii uzuale, parte din ele regsindu-se i n
exemplele ce vor fi prezentate n cuprinsul acestui capitol:

FUNCII MATEMATICE - Argumentele i rezultatul returnat sunt de tip numeric.


ROUND ( expresie_numeric, nr_zecimale )
ROUND (8.4578, 2)
Rotunjete valoarea primului argument, la numrul de
returneaz 8.46
zecimale specificat.
ABS ( expresie_numeric )
ABS (-867,34)
Returneaz valoarea absolut a unicului argument.
returneaz 867,34
FUNCII AGREGAT - Argumentele sunt reprezentate de cmpuri din tabelele bazei de date,
iar valoarea returnat este rezultatul centralizrii valorilor din aceste cmpuri.
SUM ( nume_cmp_numeric )
AVG ( nume_cmp_numeric )
MAX ( nume_cmp )
MIN ( nume_cmp )
COUNT ( nume_cmp )
Returneaz suma, media, maximul, minimul, respectiv numrul valorilor nenule din cmpul
indicat ca argument.
FUNCII PENTRU TEXTE - Argumentele sunt reprezentate de iruri de caractere.
LCASE ( ir_de_caractere )
LCASE (Baze de Date)
UCASE ( ir_de_caractere )
returneaz baze de date
Convertesc toate caracterele textului folosit ca argument n
minuscule, respectiv majuscule.

UCASE (Baze de Date)


returneaz BAZE DE DATE

LEN ( ir_de_caractere )
Returneaz lungimea unui ir de caractere.

LEN (baze de date)


returneaz 12

Baze de date
LEFT ( ir_de_caractere; nr_caractere )
RIGHT ( ir_de_caractere; nr_caractere )
MID ( ir_de_caractere; start; nr_caractere )
Returneaz un anumit numr de caractere din cadrul unui
ir, de la nceputul (LEFT), sau sfritul acestuia (RIGHT),
respectiv de la o poziie indicat explicit (MID).

3
LEFT (baze de date; 4)
returneaz primele 4 caractere:
baze
Right (baze de date; 4)
returneaz ultimele 4
date

litere:

Mid (baze de date; 6; 2)


returneaz 2 caractere, ncepnd
de la poziia a 6-a: de
FUNCII CALENDARISTICE - Argumentele sunt de tip Date/Time.
DATE () - Funcie fr argumente, care returneaz data sistemului.
NOW () - Funcie fr argumente, care returneaz data i ora sistemului.
DAY ( dat_calendaristic )
MONTH ( dat_calendaristic )
YEAR ( dat_calendaristic )
Pe baza datei indicate ca argument, se returneaz:
numrul zilei n cadrul lunii (1-31) - DAY
numrul lunii n cadrul anului (1-12) - MONTH
- anul - YEAR.
ALTE TIPURI DE FUNCII
IIF (expresie_condiional, rezultat1, rezultat2)
rezultat1 = valoare sau expresie, pentru care
expresie_condiional returneaz TRUE
rezultat2 = valoare sau expresie, pentru care
expresie_condiional returneaz FALSE
IIF (Immediate IF) evalueaz o expresie condiional a crei
valoare de adevr determin rezultatul funciei. Sunt
permise IIF-urile imbricate (la specificarea argumentelor se
pot folosi alte IIF-uri).
ISNULL (expresie)
Testeaz dac o expresie are valoarea NULL, returnnd,
dup caz, TRUE sau FALSE.

DAY (#22/12/2008#)
Returneaz 22
MONTH (#22/12/2008#)
Returneaz 12
YEAR(#22/12/2008#)
Returneaz 2008

IIF (MONTH(DATE()) = 12,


1, MONTH(DATE())+1)
Returneaz luna urmtoare
celei curente (dac ne aflm n
decembrie, urmeaz prima lun a
anului - ianuarie, n caz contrar,
urmeaz luna cu numrul egal cu
rangul lunii curente + 1).
ISNULL (Baze de date)
returneaz FALSE

Operatori Acioneaz asupra unor elemente cunoscute drept operanzi i n


funcie de specific, permit definirea unor expresii logice, calcule etc.
Operanzii pot fi reprezentai de date stocate n tabelele bazei de date, expresii
derivate pe baza acestora, constante numerice, text etc. Vom trece n revist
tipologia operatorilor din SQL, specificnd operanzii ntr-o manier generic
(A, B, C...):

OPERATORI ARITMETICI - Returneaz rezultatul unei operaii matematice.


+
A+B
Adunare

Limbajul SQL
*
/
\
^
Mod

AB
A*B
A/B
A\B
A^B
A Mod B

Scdere
nmulire
mprire
mprire ntreag; se returneaz ctul mpririi lui A la B
Ridicare la putere (A reprezint baza, iar B, exponentul)
Se returneaz restul mpririi lui A la B

OPERATORI DE COMPARARE - Returneaz o valoare logic (TRUE sau FALSE), care


depinde de relaia dintre operanzi.
<
A<B
Mai mic
<=
A < = B Mai mic sau egal
>
A > B Mai mare
>=
A >= B Mai mare sau egal
=
A=B
Egalitate
<>
A < > B Diferit
BETWEEN
A BETWEEN B AND C Verific dac A se ncadreaz n intervalul B C.
Echivalent cu: A > = B AND A < = B
IN
A IN (B, C, D, ) Verific dac A este egal cu una din valorile din list.
Echivalent cu: A = B OR A = C OR A = D
LIKE
A LIKE B
Se aplic doar operanzilor de tip text. Returneaz TRUE cnd
operandul A coincide cu B, sau cu un ablon pentru texte, definit cu ajutorul
NOT LIKE
caracterelor de nlocuire generice:
? (un caracter unic, de orice tip)
* (zero sau mai multe caractere, de orice tip)
# (un caracter unic, reprezentat de o cifr)
[list_caractere] (un singur caracter din list)
[! list_caractere] (un singur caracter, care nu se afl n list)
[list_caractere] poate conine caractere furnizate explicit sau sub form de
interval (de exemplu, [abcd] sau [a-d])

IS
IS NOT

Presupunnd c operandul A are valoarea tranzacia23, toate comparaiile


urmtoare vor returna TRUE:
A LIKE tranzacia23
A LIKE [rtz]ranzacia##
A LIKE [r-w]ran*
A LIKE [!a-m]*23
A LIKE tran[mz]?????23
A IS NULL
B IS NOT NULL
Unul dintre operanzi este NULL; permite testarea nulitii sau nenulitii
celuilalt operand.

Observaii:
- Operatorii <, >, <=, >=, Between se aplic operanzilor de tip Number, Date/Time, dar i
Text.
- n comparaiile ntre texte se folosete exclusiv criteriul alfabetic, ignorndu-se formatul
(majuscule/minuscule). Spre exemplu, comparaiile urmtoare returneaz TRUE :
abc < xyz
Abc = abc
bca > Bac

Baze de date

OPERATORI LOGICI - Se aplic operanzilor de tipul valorilor logice (expresii condiionale,


ce pot fi evaluate ca TRUE / FALSE) i returneaz tot o valoare logic.
AND
A AND B Conjuncia (I logic) - returneaz TRUE, dac valoarea logic a
ambilor operanzi este TRUE.
OR
A OR B
Disjuncia (SAU inclusiv) - returneaz TRUE dac cel puin unul
dintre operanzi are valoarea logic TRUE.
XOR
A XOR B Excluziunea (SAU exclusiv) - returneaz TRUE dac operanzii
au valori logice opuse (unul TRUE, altul FALSE).
NOT
NOT A
Negaia (NU logic) - returneaz o valoare logic opus celei a
operandului.
EQV
A EQV B Echivalena logic - returneaz TRUE dac operanzii au valori
logice similare (ambii TRUE, sau ambii FALSE).
IMP
A IMP B Implicaia logic valoarea logic returnat depinde de valoarea
de adevr a operanzilor:
Evaluare
Operand A
TRUE
TRUE
FALSE
FALSE

Evaluare
Operand B
TRUE
FALSE
TRUE
FALSE

Rezultat
TRUE
FALSE
TRUE
TRUE

OPERATORI DE CONCATENARE - Se aplic operanzilor de tip text, permind alipirea


acestora ntr-un ir de caractere unic.
A&B
A+B
n ambele variante, este returnat irul de caractere obinut prin alipirea
&
textelor utilizate ca operanzi.
+
Presupunnd c operandul A are valoarea ab, iar B are valoarea cd, n
urma concatenrii obinem abcd.

Principalele reguli de sintax aferente limbajului SQL sunt:


Un bloc de cerere SQL se termin cu semnul ;

Punctul (.) este utilizat ca separator ntre numele unui cmp i numele
tabelului din care acesta provine (NumeTabel.NumeCmp)
Parantezele drepte ([]) pot fi folosite pentru a ncadra nume de cmpuri sau de
tabele, devenind chiar obligatorii n cazul numelor purttoare de caractere
neacceptate, a celor exprimate prin cuvintele rezervate ale SQL ([SELECT],
[FROM] etc.), sau a numelor interspaiate ([Nume Tabel].[Nume Cmp]).
Virgula (,) este utilizat pentru delimitarea elementelor unei liste de atribute
(SELECT nume_atribut1, nume_atribut2, ...), tabele (FROM nume_tabel1,
nume_tabel2, ...), sau valori (WHERE nume_atribut IN (valoare1,
valoare2, ...)).
Valorile text sunt delimitate prin ghilimele (text), iar cele de tip dat/timp
sunt ncadrate de # (#2/2/2009#)

Limbajul SQL

Dei SQL este un limbaj cu format liber, care nu prescrie reguli de editare a codului,
acesta este mai uor de parcurs dac se folosesc anumite convenii:

De regul, fiecare clauz a unei cereri SQL se plaseaz pe cte o linie separat;
nceputul fiecrei clauze va fi aliniat cu nceputul celorlalte.

Dac o clauz este fragmentat, fiecare dintre prile ei constitutive se


poziioneaz pe cte o linie separat i se indenteaz fa de nceputul clauzei.

Pentru evidenierea cuvintelor rezervate, specifice SQL, se utilizeaz majuscule.

Din intenia de a prezenta limbajul SQL ntr-o manier consistent i generic,


menit s faciliteze rezolvarea oricrei cereri concrete, aplicabil oricrei baze
de date relaionale, pentru fiecare tip de cerere vom furniza cte un ablon de
sintax, la nivelul crora se folosesc urmtoarele convenii de notare:
Cuvintele rezervate sunt scrise cu majuscule, iar cele definite de utilizator cu
minuscule.
Bara vertical (|) permite separarea mai multor elemente alternative, care se
exclud reciproc (doar unul dintre acestea poate fi menionat).
Acoladele ({ }) ncadreaz un element obligatoriu.

Parantezele drepte ([ ]) ncadreaz un element opional.

Punctele de suspensie (... n) semnaleaz repetarea opional a unui element, de


n ori.

n mod concret, astfel de abloane de sintax vor fi folosite pentru definirea unor
blocuri de cerere SQL, care rspund unor necesiti informaionale concrete i a
cror implementare poate fi realizat n trei moduri distincte:
Prin ncapsularea cererilor SQL n codul-surs al unei aplicaii (Embedded
SQL);
Prin definirea unor proceduri ce conin cod SQL i care pot fi apelate de
diverse aplicaii (Modul Language);
Prin introducere direct, folosind prompterul sau interfaa grafic oferite de un
S.G.B.D. (Direct SQL).
SQL permite implementarea tuturor funcionalitilor unui S.G.B.D, legate de
definirea i manipularea coninutului unei baze de date; din aceast perspectiv,
SQL fi considerat un limbaj complet. n mod concret, cererile SQL pot fi grupate
n mai multe categorii, dintre care, cele mai importante vizeaz:
Definirea datelor - Const n descrierea i modificarea structurii bazei de
date.
Manipularea datelor - mbrac dou forme:
Consultarea datelor - Regsirea i afiarea datelor stocate n tabele,
eventual cu efectuarea unor calcule, formatri, sortri, sau alte

Baze de date

prelucrri prealabile, conform necesitilor informaionale ale


utilizatorilor bazei de date.
Actualizarea datelor - Face posibile adugarea, modificarea,
respectiv tergerea nregistrrilor din baza de date.
Controlul accesului la date - Are drept scop acordarea, respectiv revocarea
drepturilor de acces la tabelele din baza de date.
Categoriile de cereri enumerate aici vor fi prezentate pe larg n cele ce urmeaz,
pentru fiecare fiind alocat un subcapitol distinct, care red att sintaxa tipului de
cerere, ct i maniera n care aceasta poate fi aplicat pentru soluionarea unor
cerine ce vizeaz o baz de date concret.
Prezentarea sintaxei SQL va fi realizat n prim instan prin exemple cu caracter
generic, folosind o structur de date abstract, cu tabele i cmpuri fr o
semnificaie anume. n acest scop, vom recurge la tabele generice, ce se presupune
c sunt rezultatul cererilor SQL de definire a datelor prezentate n subcapitolul
urmtor (3.2 - Descrierea structurii datelor): tabele A, B, C, cu atributele a1, a2,
a3..., b1, b2 ..., c1... etc. n opinia autorilor, astfel de exemple generice faciliteaz
o bun nelegere a sintaxei SQL, nefiind grevate de complexitatea inevitabil pe
care o aduc particularitile i regulile specifice unei baze de date inspirate de
realitile unui domeniu de activitate concret.
Pe de alt parte, considernd c expresia bunei cunoateri a SQL este capacitatea
de definire a unor cereri concrete, pentru satisfacerea anumitor necesiti
informaionale, am ales ca exemplificarea elementelor de sintax s se realizeze i
prin recurgerea la o structur de date cu o mai mare aplicabilitate practic. n acest
caz, este vorba despre o baz de date ipotetic, menit a deservi un sistem
informatic pentru gestiunea tranzaciilor bursiere i care este structurat n Figura
1

Figura 1 Modelul relaional al unui sistem informatic pentru gestiunea tranzaciilor bursiere

Limbajul SQL
(Implementare S.G.D.B. Access 2007 - TranzaciiBursiere.accdb)

Figura urmtoare transfer modelul deja prezentat n planul concretului, ilustrnd,


cu titlu de exemplu, relaiile dintre nregistrrile stocate n tabele diferite,
consecine ale restriciei de integritate referenial:

3.2 Descrierea structurii datelor


n funcie de natura lor, cererile SQL pentru descrierea structurii datelor vizeaz
crearea, modificarea, respectiv tergerea tabelelor ce compun o baz de date. Se
impune precizarea c toate aceste operaii pot face obiectul restriciilor definite de
administratorul bazei de date, cu privire la drepturile de executare a anumitor
categorii de operaii, precum i la calitatea, sau rolurile utilizatorilor ce
beneficiaz de aceste drepturi.
Crearea tabelelor
Cererile SQL de acest tip trebuie s specifice numele noului tabel, numele i
tipurile de date aferente cmpurilor pe care acesta le va conine, cheia primar i
dac este cazul, ali indeci i/sau restricii la nivel de cmp sau tabel, conform
urmtoarei sintaxe:

Baze de date

CREATE TABLE Nume_Tabel


(nume_atribut tip_dat [(mrime)] [NOT NULL]
[DEFAULT valoare_implicit]
[{PRIMARY KEY | UNIQUE}] [, ... n]
[, CONSTRAINT {nume_restricie | nume_index}
{CHECK (condiie)
| PRIMARY KEY (nume_atribut [, ... n])
| UNIQUE (nume_atribut [, ... n])
| FOREIGN KEY (nume_atribut [, ... n])
REFERENCES nume_tabel_printe (nume_cmp_legtur [, ... n])
}, n ]) ;

Sunt de precizat cteva observaii pe marginea acestei sintaxe:

Numele noului tabel trebuie s fie unic la nivelul bazei de date, n timp ce
numele atributelor trebuie s fie unice la nivel de tabel.

NOT NULL impune restricia de nenulitate a unui atribut, iar DEFAULT


permite specificarea valorilor implicite.

Facem precizarea c ntre tipurile de date ce pot fi specificate ntr-o cerere


SQL i cele ce pot fi setate prin interfaa grafic din Access (Design View) nu
exist o coresponden perfect. Dintre tipurile de date frecvent utilizate,
amintim: Number (n modul Design, corespunde cu Double), Integer (Long
Integer, n modul Design), Logical (Yes/No, n modul Design), Date, Memo,
Text (n acest caz se poate indica i numrul maxim de caractere admis, de
exemplu, Text(50); dac lungimea maxim nu este precizat, se consider a fi
de 255 caractere).

n funcie de argumentele care o nsoesc, clauza CONSTRAINT are drept


scop definirea de:
Chei primare, pe unul sau mai multe cmpuri (PRIMARY KEY). n
mod implicit, pe cmpurile care compun o cheie primar se definete
un index cu numele indicat de clauza CONSTRAINT.
Chei externe, ce includ unul sau mai multe atribute (FOREIGN KEY).
Cmpurile care compun o cheie extern refer cmpurile de legtur
din tabelul corespondent, care pot fi reprezentate de chei primare, sau
indeci cu valori unice.
Indeci care nu admit duplicate (UNIQUE)
Restricii la nivel de cmp i/sau de tabel (CHECK).

Cheile primare i indecii cu valori unice pot fi definii i n mod direct, n


afara clauzei CONSTRAINT, folosind specificatorii PRIMARY KEY /
UNIQUE alturi de numele unui cmp, ns doar dac indexul / cheia primar
include un singur cmp.

10

Limbajul SQL

n cazul restriciilor CHECK i a cmpurilor de legtur FOREIGN KEY,


nume_restricie trebuie s fie unic la nivelul ntregii baze de date, n timp ce
pentru celelalte cazuri de restricii/indeci, cerina de unicitate a numelui
trebuie s se verifice la nivelul tabelului nou creat.

Numele definite de utilizator la nivelul cererii SQL (numele tabelului,


cmpurilor, restriciilor) trebuie ncadrate ntre paranteze drepte ([]), atunci
cnd conin spaii, sau cnd coincid cu anumite cuvinte rezervate (TABLE,
CONSTRAINT, UNIQUE etc.
Observaie: Dialectul SQL specific S.G.B.D.-ului Access nu permite definirea
restriciilor CHECK i a valorilor implicite, pentru folosirea acestor elemente de
sintax fiind necesar ca la nivelul bazei de date n care se execut comanda
CREATE TABLE s se opteze pentru standardul de sintax ANSI SQL-92
(Access Options Object Designers Query design: SQL Server Compatible
Syntax (ANSI92) - n cazul versiunii Access 2007).
Exemple de cereri SQL care vizeaz crearea de tabele:
Fraz SQL

Interpretare

CREATE TABLE A (
a1 INTEGER PRIMARY KEY,
a2 TEXT (30) NOT NULL,
a3 DATE DEFAULT DATE(),
a4 NUMBER NOT NULL DEFAULT 100,
a5 NUMBER,
a6 NUMBER,
CONSTRAINT chk1 CHECK (a5 > 20),
CONSTRAINT chk2 CHECK (a3 <= DATE()),
CONSTRAINT chk3 CHECK (a4 > (2 * a5)),
CONSTRAINT idx UNIQUE (a4)
);

Instruciunea permite crearea tabelei A, a crei


structur vizualizat n MS Access - Design View se
prezint astfel:
- a1 Primary Key - Data Type: Number; Field Size:
Long Integer
- a2 - Data Type: Text; Field Size: 30; Required: Yes
- a3 - Data Type: Date/Time; Default Value: DATE();
Validation Rule: <=DATE()
- a4 - Data Type: Number; Field Size: Double;
Default Value: 100; Required: Yes; Indexed: Yes
(No Duplicates)
- a5 - Data Type: Number; Field Size: Double;
Validation Rule: >20
- a6 - Data Type: Number; Field Size: Long Integer
Table Properties Validation Rule: a4 > (2 * a5)

CREATE TABLE B (
b1 INTEGER, b2 INTEGER,
a1 INTEGER,
CONSTRAINT pk PRIMARY KEY (b1, b2),
CONSTRAINT fk1 FOREIGN KEY (a1)
REFERENCES A(a1)) ;

Instruciune de creare a tabelei B, a crei structur


vizualizat n MS Access - Design View se prezint
astfel:
- b1 Primary Key - Data Type: Number; Field Size:
Long Integer
- b2 Primary Key - Data Type: Number; Field Size:
Long Integer
- a1 - Data Type: Number; Field Size: Long Integer
Instruciune pentru crearea tabelei C, a crei
structur vizualizat n MS Access - Design View se
prezint astfel:
- c1 Primary Key - Data Type: Number; Field Size:
Long Integer
- b1 - Data Type: Number; Field Size: Long Integer

CREATE TABLE C (
c1 INTEGER PRIMARY KEY,
b1 INTEGER, b2 INTEGER,
CONSTRAINT fk2 FOREIGN KEY (b1, b2)
REFERENCES B(b1, b2)) ;

Baze de date

11
- b2 - Data Type: Number; Field Size: Long Integer

tergerea unui tabel din baza de date se realizeaz printr-o cerere de tipul:
DROP TABLE nume_tabel ;

De asemenea, tabelele pot face obiectul modificrilor de structur, prin


adugarea, respectiv eliminarea unor atribute sau restricii.

Toate operaiile de editare a unei tabele ncep cu instruciunea care indic


afectarea obiectului vizat:

ALTER TABLE nume_tabel

urmat de instruciunile ce opereaz modificrile propriu-zise:

Eliminarea unui atribut:

DROP COLUMN nume_atribut

Adugarea unui atribut:

ADD COLUMN nume_atribut tip_dat [(mrime)] [NOT NULL]


[DEFAULT valoare_implicit] [{PRIMARY KEY | UNIQUE}]

Eliminarea unei restricii / index:

DROP CONSTRAINT {nume_restricie | nume_index}

Adugarea unei restricii / index:


- Restricie la nivel de cmp / tabel:

ADD CONSTRAINT nume_restricie CHECK (condiie)

- Cheie primar:
ADD CONSTRAINT nume_index PRIMARY KEY (nume_atribut [, ... n])

- Index cu valori unice:


ADD CONSTRAINT nume_index UNIQUE (nume_atribut [, ... n])

- Cheie extern:
ADD CONSTRAINT nume_relaie FOREIGN KEY (nume_atribut [, ... n])
REFERENCES nume_tabel_printe (nume_cmp_legtur [, ... n])

Alturi de modificrile de structur din categoria ALTER TABLE, se pot meniona


i cele de creare, respectiv de eliminare a indecilor definii la nivelul unui tabel,
prin cereri de tipul:
CREATE [UNIQUE] INDEX nume_index
ON nume_tabel (nume_atribut [ASC | DESC] [, ... n])

i
DROP INDEX nume_index ON nume_tabel

12

Limbajul SQL

Cererile CREATE INDEX permit definirea de indeci pe mai multe cmpuri, ale
cror realizri se pot sorta ascendent (implicit) sau descendent, accelernd astfel
regsirea datelor i rezolvarea cererilor de consultare a bazei de date.
Exemple de cereri SQL care vizeaz modificarea structurii tabelelor:
Fraz SQL

Interpretare

CREATE TABLE [Tabela D] (


[cmp d1] TEXT(30) UNIQUE,
[cmp d2] TEXT) ;

Se creeaz un nou tabel, dou cmpuri text, fr a se


defini o cheie primar. Pentru al II-lea cmp, nu se indic
numrul maxim de caractere, acesta fiind stabilit implicit
la 255. Att numele tabelului, ct i cele ale cmpurilor
conin spaii, astfel nct trebuie delimitate cu ajutorul
parantezelor [ ]. Pe atributul [cmp d1] este definit un
index cu valori unice.

CREATE INDEX i ON [Tabela D]


([cmp d1], [cmp d2]) ;

La nivelul tabelului nou creat, [Tabela D], se definete un


alt index (numit i), de aceast dat, compus i care admite
duplicate.

DROP TABLE [Tabela D] ;

Tabelul [Tabela D] este eliminat din baza de date.

ALTER TABLE B
ADD COLUMN b3 Date ;

Se modific structura tabelei B (a se vedea exemplele


aferente cererilor CREATE TABLE). Se adaug un nou
atribut, care n MS Access - Design View prezint
urmtoarele proprieti:
Field Name: b3; Data Type: Date/Time

ALTER TABLE B
ADD CONSTRAINT chk CHECK
(MONTH(b3) IN (1,5,12)
AND b3 < DATE()) ;

La nivelul tabelei B, se adug o restricie privind cmpul


b3: datele calendaristice, realizri ale acestui cmp,
trebuie s fie anterioare datei curente, iar luna aferent
acestora, Ianuarie, Mai, sau Decembrie. n MS Access Design View aceast restricie va fi prezentat astfel::
Validation Rule: MONTH (b3) IN (1,5,12) AND b3 <
DATE()

ALTER TABLE B
ADD COLUMN b4 TEXT (15)
NOT NULL DEFAULT abc ;

Se modific din nou structura tabelei B, prin adugarea


unui alt atribut, cu urmtoarele proprieti (MS Access Design View):
Field Name: b4; Data Type: Text; Field Size: 15;
Default value: abc; Required: Yes

ALTER TABLE B
DROP CONSTRAINT chk ;

n tabela B, se renun la regula de validare chk, definit


anterior la nivelul cmpului b3.

ALTER TABLE B
DROP COLUMN b4 ;

Se elimin atributul b4 din tabela B.

Baze de date

13

Considernd c toate cererile SQL exemplificate n acest subcapitol vizeaz o


baz de date unic, n urma executrii lor, structura acestei baze de date se
prezint astfel:

Figura 2 Tabele generice A, B, C i relaiile dintre acestea

(Implementare S.G.D.B. Access 2007)

Relaiile dintre tabele sunt consecina restriciilor de tip FOREIGN KEY, definite
la nivelul tabelelor B i C (a se vedea exemplele aferente cererilor CREATE
TABLE).
Observaie: Aceast structur cu caracter generic va fi utilizat, ca surs de date,
la exemplificarea altor tipuri de cereri SQL, pe care urmeaz s le prezentm n
continuarea acestui capitol.
Pentru simplificare, structura tabelelor va fi specificat sub forma urmtoare:
A ( a1, a2, a3, a4, a5, a6 )
B ( b1, b2, a1, b3 )
C ( c1, b1, b2 )

3.3 Consultarea datelor


O cerere de consultare, numit i interogare, vizeaz regsirea i afiarea anumitor
date, cu respectarea structurii, formatului i altor elemente impuse de cel care o
definete. Chiar dac, din punctul de vedere al formalismului SQL, cererile de
consultare a datelor reprezint o categorie n sine, pentru a facilita nelegerea lor,
le vom prezenta gradual, grupate n urmtoarele subcategorii:
1. Interogri simple, bazate pe un singur tabel
2. Interogri simple (fr grupri), cu centralizarea datelor dintr-un tabel unic
3. Cereri de centralizare a datelor dintr-un tabel unic, cu recurgerea la grupri
4. Interogri care implic asocieri (compuneri) de tabele
5. Subinterogri
6. Interogri UNION
7. Interogri parametrizate
8. Interogri CROSSTAB

14

Limbajul SQL

Observaie: Exemplele ce urmeaz a fi furnizate n acest subcapitol fac referire la


structura de date generic definit n subcapitolul 3.2, respectiv la baza de date
TranzaciiBursiere, prezentat n subcapitolul 3.1.

3.3.1 Interogri simple, bazate pe un singur tabel


Cererile SQL de acest tip permit interogarea datelor dintr-un tabel unic, rezultatul
constnd ntr-un alt tabel a crui crui structur i ale crui tupluri sunt prescrise
de urmtoarea sintax:
SELECT [domeniu_selecie] list_selecie
FROM nume_tabel
[WHERE list_criterii_selecie]
[ORDER BY list_criterii_sortare [sens_sortare] ] ;

unde:
list_selecie = { * | nume_cmp [AS alias] |
[AS alias] } [, ... n]
domeniu_selecie = {[ALL | DISTINCT | DISTINCTROW]
[TOP n [PERCENT]]}
sens_sortare = {ASC | DESC}

expresie

n cele ce urmeaz, este redat semnificaia fiecrui element de sintax.

Instruciunea SELECT:
- list_selecie Permite enumerarea atributelor i/sau expresiilor derivate
pe baza acestora, care vor fi afiate n setul de rezultate al interogrii:
- * - Vor fi returnate realizrile tuturor cmpurilor din tabelul surs.
- nume_cmp [AS alias] Vor fi returnate realizrile anumitor
cmpuri, indicate n mod explicit. La nivelul setului de rezultate
returnat, aceste cmpuri pot fi redenumite folosind pseudonime
(alias-uri).
- expresie [AS alias] Permite specificarea unor expresii derivate pe
baza cmpurilor din tabela-surs, precum i a alias-urilor aferente
coloanelor n care rezultatele acestor expresii vor fi afiate n setul de
nregistrri returnat de interogare (n absena unui alias, se atribuie
un nume implicit: Expr1, Expr2 etc.).
- domeniu_selecie Determin redimensionarea setului de nregistrri
obinut dup aplicarea clauzei WHERE, n funcie de natura specificatorului
utilizat:
- ALL Vor fi returnate toate nregistrrile;
- DISTINCTROW Vor fi reinute doar tuplurile unice n
ansamblul lor (unicitatea este evaluat la nivelul ntregii nregistrri,

Baze de date

15

nu doar pe baza cmpurilor afiabile, desemnate de instruciunea


SELECT);
- DISTINCT Vor fi reinute doar nregistrrile unice la nivelul
atributelor vizibile, specificate de instruciunea SELECT;
- TOP n [PERCENT] Vor fi returnate numai un anumit numr /
procent din nregistrri. Acestea corespund primelor n rnduri /
procente din ansamblul tuplurilor, sortate conform clauzei ORDER
BY; n absena acesteia, se ine seama de ordinea implicit a
nregistrrilor.

Clauza FROM: Indic tabelul ce conine cmpurile specificate de


instruciunea SELECT, constituind sursa de date a interogrii.

Clauza WHERE: Permite specificarea de restricii asupra datelor din tabelul


surs, cu afectarea numrului de nregistrri returnate de interogare.

Clauza ORDER BY: Precizeaz criteriile de sortare a nregistrrilor ce


ndeplinesc condiiile specificate n clauza WHERE i, n mod uzual, sunt
exprimate sub forma numelor de cmpuri, sau a expresiilor derivate pe baza
acestora. O alt modalitate de indicare a unui cmp drept criteriu de sortare a
nregistrrilor este prin indicarea poziiei sale n ansamblul atributelor
tabelului-surs (spre exemplu, ORDER BY 3 ordonarea se va realiza dup
valorile celui de-al treilea atribut; ORDER BY 3, 5 se folosesc dou criterii
de sortare: al treilea, respectiv al cincilea atribut). n cazul criteriilor de sortare
multiple, succesiunea aplicrii acestora este determinat de ordinea
menionrii n clauza ORDER BY. Sensul sortrii se indic prin ASC
(ascendent), sau DESC (descendent) i dac nu este precizat, ordonarea se
realizeaz n sens ascendent.

Observaie: Dei ar putea simplifica unele clauze precum WHERE, ORDER BY


i altele ce vor fi prezentate ulterior (GROUP BY, HAVING), atunci cnd acestea
conin expresiile pe care el le desemneaz, un alias nu mai poate fi (re)utilizat n
cadrul blocului de cerere n care a fost definit. O astfel de restricie este
determinat de mecanismul de execuie al unei fraze SQL, care impune o anumit
succesiune de evaluare a clauzelor: FROM, WHERE, respectiv ORDER BY i
abia apoi specificarea cmpurilor vizibile i a alias-urilor aferente, prin
SELECT....
n concluzie, fiind definite ulterior, alias-urile nu sunt disponibile la momentul
specificrii condiiilor (WHERE), sau criteriilor de sortare a nregistrrilor
(ORDER BY) i nu pot fi utilizate n acest scop. Pentru a explica pe larg logica
execuiei unei fraze SQL definite n scopul consultrii datelor, considerm
urmtoarea cerin i echivalentul su SQL:

16

Limbajul SQL

S se returneze datele aferente societilor din Bucureti (CodSocietate, Denumire,


CapitalSocial), cu un nivel al capitalului social cuprins ntre 50.000 RON i 100.000 RON;
ordonare descresctoare, dup valoarea capitalului.
SELECT CodSocietate, Denumire, (NrAciuniEmise * ValoareNominal) AS CapitalSocial
FROM Societate
WHERE LocalitateSocietate = Bucureti
AND (NrAciuniEmise * ValoareNominal) BETWEEN 50000 AND 100000
ORDER BY (NrAciuniEmise * ValoareNominal) DESC ;

Mecanismul de execuie al unui bloc de cerere cu o astfel de sintax va fi explicat


plecnd de la premisa c dispunem de urmtoarele nregistrri:
Tabela Societate

Secvena de pai care trebuie parcurs pentru executarea frazei SQL prezentate
mai sus este urmtoarea:
1. Clauza FROM - Se stabilete sursa de date a interogrii n acest caz, este
vizat exclusiv tabelul Societate.
2. Clauza WHERE - Se filtreaz nregistrrile, reinndu-se doar datele
privind societile din Bucureti, cu capitalul cuprins ntre 50.000 i
100.000 RON:

Observaie: nregistrrile bifate sunt marcate pentru tergere.


3. Clauza ORDER BY - Se sorteaz nregistrrile rmase, de la cea mai mare,
ctre cea mai mic valoare a capitalului social:
Cod
Societate

Denumire

Localitate
Societate

189
533

Naturalis
TransTour

Bucureti
Bucureti

...

NrAciuni
Emise

Valoare
Nominal

200.000
75.000

0,50
0,80

CapitalSocial =
( NrAciuniEmise *
ValoareNominal )
100.000
60.000

4. Instruciunea SELECT - Este returnat setul de nregistrri obinut prin


parcurgerea etapelor anterioare, fiind reinute pentru afiare cmpurile

Baze de date

17

CodSocietate i Denumire, precum i expresia de calcul a capitalului, cu


alias-ul CapitalSocial:
CodSocietate
189
533

Denumire
Naturalis
TransTour

CapitalSocial
100.000
60.000

Devine deci evident c, dei utilizat drept criteriu de filtrare, respectiv de


sortare a nregistrrilor, n clauzele - deja evaluate - WHERE i ORDER BY,
capitalul social nu putea fi desemnat prin intermediul alias-ului abia acum
definit (dei ar fi fost mai comod), ci doar prin specificarea expresiei de
calcul ce st la baza sa.
Exemple de interogri folosesc ca surs de date tabelul generic A, definit n
subcapitolul 3.2: A (a1, a2, a3, a4, a5, a6)
Fraz SQL
SELECT TOP 20 PERCENT *
FROM A
ORDER BY a5, a2 DESC ;
Observaie: Un rezultat similar se obine i dac
n clauza ORDER BY se indic poziia
cmpurilor-criterii de sortare n cadrul tabelului
surs:
ORDER BY 5, 2 DESC ;
SELECT DISTINCT a2, a3
FROM A ;

Interpretare
Sunt selectate primele 20% din nregistrrile
tabelului A, rezultatele fiind sortate cresctor,
dup a5 i descresctor, dup a2. Se vor
afia toate cmpurile din structura tabelului.

Sunt returnate realizrile cmpurilor a2 i


a3, cu eliminarea rndurilor duplicate.

SELECT a1, a2, a5


FROM A
WHERE a4 > a1
AND a6 LIKE *text*
AND YEAR (a3) IN (1995, 2002, 2005) ;

Selectarea cmpurilor a1, a2, a5, cu


reinerea tuplurilor ce ndeplinesc condiiile:
a4 > a1, valorile cmpului text a2 includ
irul de caractere text, iar anii extrai pe
baza datelor din cmpul a3 pot fi 1995,
2002, sau 2005.

SELECT a1, a5 AS [Valoare T0],


a4 AS [Valoare T1],
a4 - a5 AS [Diferena absolut],
(a4 - a5) / a5 AS [Diferena relativ]
FROM A
WHERE (a4 - a5) / a5 BETWEEN 0.2 AND 0.5
OR (a4 - a5) / a5 > 0.8
ORDER BY (a4 - a5) / a5 DESC, a4 - a5 ASC ;

Selectarea cmpurilor a1, a5 (numit Valoare


T0), a4 (Valoare T1) i a expresiilor a4-a5
(diferena absolut) i (a4-a5)/a5 (diferena
relativ), pentru nregistrrile n cazul crora
diferena relativ fie se ncadreaz ntre 20%
- 50%, fie depete 80%. Rezultatele vor fi
sortare descresctor, dup diferena relativ
i cresctor, dup cea absolut.

Exemple de cereri de consultare a bazei de date TranzaciiBursiere, prezentat n


subcapitolul 3.1:

18

Limbajul SQL

1
S se returneze brokerii care s-au angajat n ultimii 3 ani, ordonai descresctor, dup data
angajrii.
SELECT * FROM Broker
WHERE YEAR(DatAngajare) > = (YEAR (DATE()) 3)
ORDER BY DatAngajare DESC ;
2
S se obin o list a clienilor persoane juridice din Iai, Braov i Arad; ordonare dup
localitile i numele clienilor.
SELECT * FROM Client
WHERE LocalitateClient IN (Iai, Braov, Arad) AND TipClient = Persoan Juridic
ORDER BY LocalitateClient, NumeClient ;
3
S se obin o list, sortat alfabetic, a localitilor de provenien a clienilor persoane fizice.
SELECT DISTINCT LocalitateClient FROM Client
WHERE TipClient = Persoan Fizic
ORDER BY LocalitateClient ;
Observaie: ntruct nu a fost selectat pentru afiare dect atributul LocalitateClient i este posibil
ca mai muli clieni persoane fizice s domicilieze n aceeai localitate, n setul de rezultate al
interogrii pot aprea nregistrri duplicate. Specificatorul DISTINCT elimin duplicatele,
determinnd afiarea fiecrei localiti o singur dat.
4

Sub aspectul numrului de aciuni emise, s se identifice primele 10 societi ale cror titluri
au o valoare nominal de cel puin 5 RON.
SELECT TOP 10 CodSocietate, Denumire
FROM Societate
WHERE ValoareNominal > = 5
ORDER BY NrAciuniEmise DESC ;

3.3.2 Interogri ce permit centralizarea datelor dintr-un tabel unic, fr


recurgerea la grupri
Astfel de cereri permit agregarea datelor dintr-un anumit tabel, potrivit urmtoarei
sintaxe:
SELECT list_selecie
FROM nume_tabel
[WHERE list_criterii_selecie]

unde:
list_selecie ={AVG|COUNT|MAX|MIN|SUM({nume_cmp | expresie})
[AS alias]} [, ... n]

Semnificaia elementelor de sintax este urmtoarea:

Instruciunea SELECT: list_selecie specific funciile agregat, precum i


atributele sau expresiile derivate pe baza acestora, care fac obiectul
centralizrii. Se pot folosi funciile:

Baze de date

19

- COUNT n funcie de argument, returneaz numrul tuplurilor din


tabelul surs: COUNT(*), sau al realizrilor nenule ale unui anumit
atribut: COUNT(nume_cmp);
- SUM suma valorilor dintr-un cmp numeric;
- AVG media valorilor dintr-un cmp numeric;
- MAX maximul valorilor dintr-un cmp;
- MIN minimul valorilor dintr-un cmp.
Clauza FROM: Indic tabela ce constituie sursa de date a interogrii.
Clauza WHERE: Permite specificarea de restricii asupra nregistrrilor din
tabelul surs, centralizrile efectuate prin intermediul funciilor-agregat fiind
operate exclusiv asupra tuplurilor ce se conformeaz acestor restricii.

Observaie: Interogrile de acest tip returneaz o singur nregistrare, care conine


valorile-agregat obinute n urma centralizrilor.
Exemplu de interogare definit pe baza de date TranzaciiBursiere, prezentat n
subcapitolul 3.1:
S se calculeze vechimea medie a brokerilor, la nivelul anului 2008.
SELECT AVG (2008-YEAR(DatAngajare)) AS VechimeMedie
FROM Broker
WHERE YEAR(DatAngajare) < 2008 ;

Pentru a explica mecanismul de execuie al acestei cereri, considerm c


dispunem de urmtoarele nregistrri:
Tabela Broker

Etapele care trebuie parcurse pentru executarea frazei SQL sunt urmtoarele:
1. Clauza FROM Se stabilete sursa de date a interogrii n acest caz,
tabela Broker.
2. Clauza WHERE - nregistrrile sunt filtrate, reinndu-se doar brokerii
care au fost angajai anterior anului 2008 (pentru a putea calcula vechimea
medie la nivelul anului acestui an):

20

Limbajul SQL

Observaie: nregistrarea bifat este marcat pentru tergere.


3. Pentru nregistrrile reinute, se calculeaz vechimea, ca numr de ani de
la data angajrii, considernd 2008 ca an de referin.
Cod
Broker
189
332
444
533
677

Nume
Broker

Prenume
Broker

Popa
Rusu
Dinu
Toma
Radu

Ion
Cristian
Dan
Mircea
Dan

...

Dat
Angajare

AnAngajare =
YEAR(DatAngajare)

02.02.2001
18.09.2007
01.09.2006
11.04.2004
18.09.2004

2001
2007
2006
2004
2004

Vechime =
2008 AnAngajare
7
1
2
4
4

4. Instruciunea SELECT Se centralizeaz valorile corespunztoare


vechimii brokerilor, prin aplicarea funciei AVG. Rezultatul red vechimea
medie, calculat la nivelul anului 2008 i afiat cu alias-ul VechimeMedie:
VechimeMedie
3,6

Exemple ce folosesc ca surs de date tabelul generic A, definit n subcapitolul 3.2:


A (a1, a2, a3, a4, a5, a6)
Fraz SQL
SELECT MAX (a4) AS ValoareMaxim,
MIN (a4) AS ValoareMinim,
AVG (a4) AS ValoareMedie
FROM A
WHERE a5 IS NOT NULL ;

Interpretare
Se returneaz valoarea maxim, minim
i medie a lui a4, n condiiile n care a5
are valori nenule.

SELECT COUNT (*) AS Nrnregistrri


FROM A
WHERE (a4 - a5) / a5 > 0.75 ;

Sunt numrate tuplurile pentru care


valoarea cmpului a4 este superioar
valorii cmpului a5, cu cel puin 75%.

SELECT SUM (a4) AS [Valoare Total],


AVG (a4) AS [ValoareMedie]
FROM A
WHERE a6 BETWEEN 50 AND 100 ;

Se calculeaz suma i media valorilor din


cmpul a4, pentru care valorile
corespondente din cmpul a6 se
ncadreaz ntre 50 i 100.

Exemple de cereri de agregare a datelor, definite pe baza de date


TranzaciiBursiere:

Baze de date

21

S se determine numrul clienilor persoane juridice, cu excepia celor din Bucureti, care
nc nu beneficiaz de reprezentarea unui broker.
SELECT COUNT (*)
FROM Client
WHERE TipClient = Persoan Juridic
AND LocalitateClient < > Bucureti
AND CodBroker IS NULL ;
S se calculeze valoarea nominal medie, numrul mediu i valoarea total a aciunilor emise
de societile din Bucureti, cu capitalul social mai mare de 50.000 RON.
SELECT AVG (ValoareNominal) AS ValNominalMedie,
AVG (NrAciuniEmise) AS NrMediuAciuni,
SUM (ValoareNominal * NrAciuniEmise) AS TotalValoare
FROM Societate
WHERE LocalitateSocietate = Bucureti
AND (NrAciuniEmise * ValoareNominal) > 50000 ;

3.3.3 Interogri ce permit agregarea datelor dintr-un tabel unic, cu


recurgerea la grupri
Ca i cererile SQL prezentate anterior, acest tip de interogri vizeaz centralizarea
datelor, dar sunt mai complexe, ntruct admit criterii de grupare i dup caz,
restricii, respectiv sortri, aplicate grupurilor i valorilor-agregat, potrivit sintaxei
urmtoare:
SELECT [list_criterii_grupare] [list_valori_agregat]
FROM nume_tabel
[WHERE list_criterii_selecie_pre-agregare]
GROUP BY list_criterii_grupare
[HAVING list_criterii_selecie_post-agregare]
[ORDER BY list_criterii_sortare_post-agregare [sens_sortare];

unde:

list_valori_agregat = {AVG|COUNT|MAX|MIN|SUM
({nume_cmp | expresie}) [AS alias]}[, ... n]

Instruciunea SELECT Permite specificarea cmpurilor afiabile: valorileagregat, obinute prin aciunea funciilor centralizatoare, respectiv criteriile de
grupare la care acestea se aplic (atribute ale tabelului-surs i/sau expresii
derivate pe baza acestora).
Clauza FROM - Indic tabelul ce constituie sursa de date a interogrii.
Clauza WHERE - Permite specificarea de restricii asupra nregistrrilor din
tabelul surs, centralizrile efectuate prin intermediul funciilor agregat fiind
operate exclusiv asupra tuplurilor ce se conformeaz acestor restricii.
Clauza GROUP BY - Indic atributele/expresiile pe baza crora se va realiza
gruparea nregistrrilor tabelului-surs. Pentru fiecare valoare distinct a
criteriului de grupare, sau combinaie de valori distincte asociate criteriilor

22

Limbajul SQL
multiple, se formeaz grupuri de tupluri care prezint valori identice la nivelul
atributelor/expresiilor indicate drept criterii de grupare.
Clauza HAVING - Permite specificarea criteriilor de selecie a grupurilor de
nregistrri rezultate prin aplicarea clauzei GROUP BY.
Clauza ORDER BY - Furnizeaz criteriile de sortare a grupurilor de
nregistrri rezultate prin aplicarea clauzei GROUP BY.

Observaie: ntruct acioneaz ulterior gruprii realizate de GROUP BY, clauzele


HAVING i ORDER BY permit filtrarea, respectiv sortarea nregistrrilor, n baza
criteriilor de grupare i/sau a valorilor obinute prin centralizare. Drept urmare,
nici HAVING, i nici ORDER BY, nu permit specificarea unor atribute/expresii
care devin inaccesibile ulterior agregrii (n aceast categorie se ncadreaz toate
cmpurile din tabelul-surs, ce nu sunt menionate n clauza GROUP BY, precum
i expresiile derivate pe baza acestora, cu excepia valorilor-agregat).
Mecanismul de execuie al frazelor SQL de acest tip va fi explicat pe baza unei
cerine care vizeaz baza de date TranzaciiBursiere, prezentat n subcapitolul
3.1:
S se determine localitile la nivelul crora exist cel puin 2 societi cu un nivel al capitalului
social de cel puin 100.000 RON.
SELECT LocalitateSocietate, COUNT(*) AS [Numr societi]
FROM Societate
WHERE (NrAciuniEmise * ValoareNominal) >=100000
GROUP BY LocalitateSocietate
HAVING COUNT(*) >= 2
ORDER BY COUNT(*) DESC ;

Secvena de pai necesar executrii blocului SQL este urmtoarea:


1. Clauza FROM Se stabilete sursa de date a interogrii n acest caz,
tabela Societate. Presupunem c dispunem de urmtoarele nregistrri:
Tabela Societate

2. Clauza WHERE - Se rein doar nregistrrile n cazul crora capitalul


social, determinat ca produs ntre valoarea nominal a unei aciuni i
numrul aciunilor emise, este de cel puin 100.000 RON:

Baze de date

23

Observaie: nregistrarea bifat este marcat pentru tergere.


3. Clauza GROUP BY - nregistrrile rmase sunt ordonate dup valorile
criteriului de grupare (LocalitateSocietate), pentru fiecare valoare
distinct a acestuia, constituindu-se cte un grup de tupluri:
Localitate
Societate
Braov
Bucureti
Constana

Cod
Societate
100
300
700
200
400
600

Denumire

...

Montana
Carpai
PaniCom
Tomis
Dunrea
Flamingo

NrAciuni
Emise

Valoare
Nominal

200.000
575.000
563.000
340.000
634.000
245.000

0,50
3,00
1,65
2,50
1,75
0,75

CapitalSocial =
( NrAciuniEmise *
ValoareNominal )
100.000
1.725.000
928.950
850.000
1.109.500
183.750

4. Clauza HAVING - Asupra grupurilor obinute, se aplic funcia-agregat


COUNT, fiind reinute grupurile cu minim dou nregistrri. ntruct
datele fiecrei societi sunt redate la nivelul unei anumite nregistrri din
tabel, numrul tuplurilor aferente fiecrei valori distincte a atributului
LocalitateSocietate corespunde practic numrului societilor ce ntrunesc
condiiile specificate prin clauza WHERE. ntruct intereseaz localitile
n care sunt amplasate cel puin dou societi cu capitalul mai mare de
100.000 RON, sunt filtrate grupurile constituite n prealabil:

Observaie: nregistrarea bifat este marcat pentru tergere.


5. Clauza ORDER BY - Grupurile rmase sunt sortate descresctor, n
funcie de numrul nregistrrilor pe care le includ:
LocalitateSocietate
Constana
Braov

COUNT (*)
3
2

24

Limbajul SQL
6. Instruciunea SELECT - Este furnizat rezultatul, sub forma unui set de
nregistrri sortat conform clauzei ORDER BY; acesta conine valorile
distincte ale atributului LocalitateSocietate (rmase n urma filtrului
HAVING), precum i numrul nregistrrilor din grupurile constituite
pentru fiecare dintre aceste valori, afiat cu alias-ul Numr societi.
LocalitateSocietate
Constana
Braov

Numr societi
3
2

Exemple de interogri folosesc ca surs de date tabelul generic A, definit n


subcapitolul 3.2: A (a1, a2, a3, a4, a5, a6)
Fraz SQL
SELECT a2, a4, SUM (a6) AS Sum,
AVG (a6) AS Medie
FROM A
WHERE a6 > 0
GROUP BY a2, a4 ;

Interpretare
La nivelul valorilor distincte ale atributelor
a2 i a4, se calculeaz media i suma
realizrilor pozitive ale cmpului a6.

SELECT a2, COUNT(*) AS Nrnregistrri


FROM A
WHERE a6 IN (a4, b5)
GROUP BY a2
HAVING SUM(a6) < SUM(a4) AND
SUM(a6) < SUM(a5) ;
SELECT a2,
AVG (IIF (a4 > a6, a4 - a6, a6 - a4)) AS Medie
FROM A
WHERE a4 < > a6
GROUP BY a2
HAVING COUNT (*) > = 10
ORDER BY AVG (IIF (a4 > a6, a4 - a6, a6 - a4)) ;

La nivelul realizrilor distincte ale


cmpului a2, se determin numrul
nregistrrilor pentru care valorile lui a6
coincid cu cele ale atributelor a4 sau a5, n
timp ce suma valorilor lui a6 este
inferioar sumei valorilor din a4 i a5.
La nivelul valorilor distincte ale cmpului
a2, se calculeaz media diferenelor dintre
a4 i a6 (dac a4 > a6), sau dintre a6 i
a4 (dac a4 < a6), n cazul n care
realizrile celor dou atribute difer (a4 <
> a6). Mediile se determin doar dac
exist cel puin 10 nregistrri care satisfac
restricia menionat anterior. Rezultatele
sunt ordonate cresctor, dup medie.

Exemplu de interogri definite pe baza de date TranzaciiBursiere, prezentat n


subcapitolul 3.1:
1
S se determine numrul tranzaciilor derulate la nivelul fiecrei luni a anului precedent.
SELECT MONTH(DatTranzacie) AS Lun,
COUNT(*) AS NrTranzacii
FROM Tranzacie
WHERE YEAR(DatTranzacie) = YEAR(DATE()) -1
GROUP BY MONTH(DatTranzacie) ;
2
S se afieze localitile cu cel puin 50 de clieni persoane juridice, ordonate descresctor,
dup numrul persoanelor juridice.

Baze de date

25

SELECT LocalitateClient, COUNT(*) AS NrPJ


FROM Client
WHERE TipClient = Persoan Juridic
GROUP BY LocalitateClient
HAVING COUNT(*) >= 50
ORDER BY COUNT(*) DESC ;
3
S se determine numrul brokerilor care s-au angajat n fiecare din ultimii 3 ani.
SELECT YEAR(DatAngajare) AS AnAngajare, COUNT(*) AS NrBrokeri
FROM Broker
GROUP BY YEAR(DatAngajare)
HAVING YEAR(DatAngajare) >= (YEAR(DATE()) 3) ;
Echivalent cu:
SELECT YEAR(DatAngajare) AS AnAngajare, COUNT(*) AS NrBrokeri
FROM Broker
WHERE YEAR(DatAngajare) >= (YEAR(DATE()) 3)
GROUP BY YEAR(DatAngajare) ;
Observaie: Dei rezultatul lor este identic, diferena dintre cele dou interogri se manifest n
planul execuiei:
n primul caz, grupurile se constituie pentru fiecare valoare a anului angajrii, inclusiv
pentru anii anteriori ultimilor 3. Ulterior gruprii, acioneaz clauza HAVING, care elimin
grupurile ce vizeaz anii ce nu se conformeaz restriciei.
n al doilea caz, clauza WHERE, care acioneaz anterior gruprii, elimin nregistrrile
pentru care DataAngajrii nu aparine ultimilor 3 ani, astfel nct gruparea vizeaz exclusiv
nregistrri ce se conformeaz condiiei specificate n cerin. ntruct evit constituirea unor
grupuri inutile, aceast rezolvare este considerat mai eficient.

3.3.4 Interogri care implic compuneri (jonciuni) de tabele


Dei n cazul interogrilor prezentate pn acum sursa de date este reprezentat de
o tabel unic, exist multiple situaii care impun corelarea datelor din tabele
diferite. O astfel de operaie, numit jonciune sau compunere, conecteaz
nregistrrile din dou sau mai multe tabele, n baza anumitor condiii de
jonciune, genernd rezultate sub forma unui alt tabel, ale crui tupluri verific
respectivele condiii.
Condiiile de jonciune sunt exprimate prin comparaii (<, <=, >, >=, < >,
BETWEEN, LIKE, IN) ntre valorile unuia sau mai multor atribute dintr-o
anumit tabel i realizrile unuia, sau mai multor cmpuri, dintr-o alt tabel.
Impunerea condiiei de egalitate (=) permite implementarea compunerilor
echivalente, (echicompuneri, echijonciuni); ceilali operatori de comparaie
determin compuneri neechivalente.

26

Limbajul SQL

n mod uzual, compunerile de tabele au la baz relaii de tipul cheie primar


cheie extern, condiia de jonciune viznd egalitatea valorilor din cmpurile
asociate (echicompunere); cu alte cuvinte, liniile tabelelor care particip la
compunere sunt corelate pe baza valorilor identice ale cmpurilor de legtur.
Spre exemplu, tabelele generice A i B, definite n subcapitolul 3.2, pot fi corelate
pe baza valorilor cmpului a1, care este cheie primar n A i cheie extern n B:
A (a1, a2, a3, a4, a5, a6)
B (b1, b2, a1, b3)
Dintr-o alt perspectiv, compunerile se submpart n interne (INNER JOIN) i
externe (OUTER JOIN): cele externe produc linii n setul de rezultate chiar i
cnd condiia de jonciune nu este verificat, ceea ce nu este valabil n cazul
compunerilor interne. Spre exemplu, n cazul tabelelor A i B, compunerile se pot
defini astfel:
- INNER JOIN: Liniile celor dou tabele se combin pe baza valorilor identice
ale cmpurilor de legtur.
A INNER JOIN B ON A.a1 = B.a1

- {LEFT | RIGHT} [OUTER] JOIN: Setul de nregistrri rezultat din compunere


conine liniile celor dou tabele, combinate pe baza valorilor identice ale
cmpurilor de legtur, la care se adaug nregistrrile fr corespondent din
tabelul care constituie, dup caz, fie latura stng a compunerii, fie pe cea
dreapt. Specificatorul OUTER este opional. Compunerile urmtoare produc
acelai rezultat:
A
B

LEFT JOIN B ON A.a1 = B.a1


RIGHT JOIN A ON B.a1 = A.a1

n ambele cazuri, se obine un tabel care conine rezultatul jonciunii interne a


tabelelor A i B, plus nregistrrile din A, fr corespondent n B. De asemenea,
urmtoarele dou compuneri sunt echivalente, determinnd obinerea unui tabel
ce conine rezultatul jonciunii interne a tabelelor A i B, plus nregistrrile din
B, fr corespondent n A:
B LEFT JOIN A ON B.a1 = A.a1
A RIGHT JOIN B ON A.a1 = B.a1

Observaie: Dei relaia dintre tabele i restricia de integritate referenial


impune ca valorile cmpului cheie extern a1, din tabela B, s se regseasc
printre cele ale cmpului a1, cheie primar n tabelul A, atributul B.a1 admite i
valori nule (cu alte cuvinte, valori fr corespondent printre valorile A.a1).
Dup cum se poate deduce din exemplele de mai sus, poziionarea tabelelor ce
particip la asociere fa de operatorul INNER JOIN este irelevant (A INNER
JOIN B i B INNER JOIN A sunt construcii echivalente), dar n cazul

Baze de date

27

compunerilor externe, poziia tabelelor are un rol determinant (A {LEFT|


RIGHT} JOIN B i B {LEFT|RIGHT} JOIN A produc rezultate diferite).
n concluzie, sintaxa generic a interogrilor ce includ compuneri de tabele este
urmtoarea:
SELECT [domeniu_selecie] list_selecie
FROM nume_tabel1
{INNER|LEFT[OUTER]|RIGHT[OUTER]}JOIN
ON condiie_jonciune
[WHERE list_criterii_selecie] ;

nume_tabel2

unde:
list_selecie = { * | nume_cmp [AS alias] | expresie [AS alias]} [, ... n]
domeniu_selecie = {[ALL|DISTINCT|DISTINCTROW] [TOP n [PERCENT]]}
O alternativ la compunerile interne definite pe baza operatorului INNER JOIN
este oferit de sintaxa urmtoare:
SELECT [domeniu_selecie] list_selecie
FROM nume_tabel1, nume_tabel2 [, ... n]
WHERE condiie_jonciune [AND list_criterii_selecie] ;

n acest caz, ntr-o prim faz, nregistrrile unui tabel se combin rnd pe rnd cu
toate nregistrrile din cellalt tabel (realizndu-se operaia numit produs
cartezian), relaia dintre nregistrrile celor dou tabele fiind stabilit ulterior, prin
condiia de jonciune specificat n clauza WHERE.
Observaii:
Argumentul condiie_jonciune indic maniera n care nregistrrile din
tabelele surs pot fi asociate pe baza cmpurilor de legtur:
nume_tabel1.nume_atributA1 = nume_tabel2.nume_atributA2
Argumentul list_criterii_selecie permite specificarea de filtre asupra
setului de nregistrri generat n urma jonciunii.
ntruct n seciunea curent intereseaz n mod particular aspectele legate
de compunerile de tabele, sintaxa generic de mai sus este redat ntr-o
form simplificat. Facem ns precizarea c i n cazul interogrilor cu
mai multe tabele surs se poate recurge la centralizri i/sau sortri de
date, adugndu-se, dup caz, funcii agregat, clauzele GROUP BY,
HAVING, ORDER BY.
n situaia n care tabele distincte, folosite ca surs a aceleiai interogri
conin cmpuri cu nume identice, specificarea atributelor respective se va
realiza prin indicarea tabelelor din care provin: nume_cmp.Nume_Tabel
O interogare poate avea drept surs mai mult de dou tabele: rezultatul
compunerii a dou tabele T1 i T2 poate fi compus cu T3, tabelul rezultat

28

Limbajul SQL
fiind compus mai departe cu T4 etc. Vom exemplifica, pe baza tabelelor
generice A, B, C, definite n subcapitolul 3.2:

Plecnd de la relaiile stabilite pe baza cheilor externe, furnizm trei


exemple de asociere a datelor din cele trei tabele, prin:
a) Jonciune intern
SELECT A.a1, a2, a4, B.b1, B.b2, c1
FROM A INNER JOIN
(B INNER JOIN C ON (B.b1 = C.b1 AND B.b2 = C.b2))
ON A.a1=B.a1 ;

sau:
SELECT A.a1, a2, a4, B.b1, B.b2, c1
FROM A, B, C
WHERE A.a1=B.a1 AND B.b1 = C.b1 AND B.b2 = C.b2 ;

b) Jonciune extern

SELECT A.a1, a2, a4, B.b1, B.b2, c1


FROM A LEFT JOIN
(B LEFT JOIN C ON (B.b1 = C.b1 AND B.b2 = C.b2))
ON A.a1=B.a1 ;

Observaie: ntruct cheia primar a tabelei B, respectiv cheia extern


corespondent din tabela C, sunt compuse din dou atribute (b1, b2), jonciunea
tabelelor B i C trebuie realizat pe baza a dou criterii de compunere (B.b1 =
C.b1 AND B.b2 = C.b2)
Mecanismul de execuie al frazelor SQL, care implic jonciuni de tabele va fi
explicat pe baza unei cerine care vizeaz baza de date TranzaciiBursiere,
prezentat n subcapitolul 3.1. S presupunem c dispunem de urmtoarele
nregistrri:
Tabela Broker

Tabela Client

Baze de date

29

S se afieze codul, numele i prenumele brokerilor care reprezint clieni din Braov.
Sintaxa A:
SELECT DISTINCT Broker.CodBroker, NumeBroker, PrenumeBroker
FROM Broker INNER JOIN Client
ON Broker.CodBroker = Client.CodBroker
WHERE LocalitateClient = Braov;
Sintaxa B:
SELECT DISTINCT Broker.CodBroker, NumeBroker, PrenumeBroker FROM Broker, Client
WHERE Broker.CodBroker = Client.CodBroker
AND LocalitateClient = Braov ;
Observaie: ntruct atributul CodBroker se regsete n ambele tabele, simpla menionare a
numelui su (SELECT CodBroker ...) nu este suficient, fiind necesar s i se precizeze
proveniena - tabela Broker, sau tabela Client. ntruct exemplul de fa ilustreaz o compunere
intern, cmpul de legtur fiind chiar CodBroker (Broker.CodBroker = Client.CodBroker),
indiferent de tabelul specificat, rezultatul este acelai.

Pentru rezolvarea cerinei de mai sus, au fost definite dou fraze SQL care produc
acelai rezultat, dar care difer prin maniera de realizare a compunerii tabelelor
surs (cu sau fr operatorul JOIN). n cele ce urmeaz vom prezenta secvena de
pai necesar execuiei ambelor blocuri SQL.
Mecanismul de execuie al frazei SQL care se conformeaz sintaxei A:
1. Clauza FROM Se stabilete sursa de date a interogrii - n acest caz, este
vorba de rezultatul compunerii tabelelor Broker i Client, pe baza valorilor
identice din cmpurile de legtur (echicompunere). Drept urmare, nu vor
fi reinute nregistrrile din tabela Broker, fr corespondent n tabela
Client (brokerul cu codul 211). Tabelul rezultat conine urmtoarele
nregistrri:
Cod
Broker
189
533
533
189

Tabela Broker
Nume
Prenume
Broker
Broker
Popescu Ion
Toma
Mircea
Toma
Mircea
Popescu Ion

...

Cod
Client
100
300
500
600

...

Tabela Client
Nume
Cod
...
Client
Broker
Montana SA
189
Alpin SRL
533
MoldoTrans SA
533
Carpai SA
189

...

Localitate
Client
Braov
Braov
Iai
Braov

2. Clauza WHERE Se filtreaz tuplurile tabelului rezultat n urma


compunerii, reinndu-se nregistrrile care privesc clienii din Braov:
Cod
Broker

Tabela Broker
Nume
Prenume
Broker
Broker

Tabela Client
...

Cod
Client

...

Nume
Client

...

Cod
Broker

...

Localitate
Client

30

Limbajul SQL
189
533
189

Popescu
Toma
Popescu

Ion
Mircea
Ion

100
300
600

Montana SA
Alpin SRL
Carpai SA

189
533
189

Braov
Braov
Braov

3. Instruciunea SELECT Pe baza nregistrrilor pstrate ulterior


compunerii i aplicrii restriciilor din clauza WHERE, sunt afiate
realizrile anumitor cmpuri din tabelul Broker (SELECT
Broker.CodBroker, NumeBroker, PrenumeBroker):
CodBroker
189
533
189

NumeBroker
Popescu
Toma
Popescu

PrenumeBroker
Ion
Mircea
Ion

Se poate observa c n tabelul rezultat n urma compunerii, numrul apariiilor


unui broker coincide cu numrul clienilor si; pe de alt parte, nregistrrile
privitoare la un anumit broker pot fi difereniate unele de altele pe baza
cmpurilor provenite din tabelul Client. n cazul nostru ns, din tabelul
rezultat prin compunere vor fi decupate spre a fi afiate doar atribute ce
provin din tabelul Broker, ceea ce conduce la apariia duplicatelor spre
exemplu, datele brokerului cu codul 189 vor fi afiate de dou ori. Pentru
eliminarea duplicatelor la nivelul cmpurilor vizibile, a fost utilizat
specificatorul DISTINCT, care determin urmtorul rezultat final:
CodBroker
189
533

NumeBroker
Popescu
Toma

PrenumeBroker
Ion
Mircea

Utilizarea specificatorul DISTINCTROW nu ar fi avut nici un efect, ntruct


acesta permite eliminarea duplicatelor la nivel de nregistrare, lund n calcul
i cmpurile neafiabile. n exemplul prezentat, ns, tabelul rezultat n urma
compunerii nu conine duplicate, unicitatea tuplurilor sale fiind asigurat de
combinaia dintre codurile brokerilor i cele ale clienilor (cheile primare ale
tabelelor asociate).
Mecanismul de execuie al frazei SQL care se conformeaz sintaxei B:
1. Se stabilete sursa de date a interogrii (Clauza FROM). n acest caz, este
vorba de rezultatul compunerii tabelelor Broker i Client prin produs
cartezian (a se vedea subcapitolul 3.6). Practic, fiecare nregistrare din
tabela Broker este combinat cu fiecare tuplu al tabelei Client, fr a se
ine seama de valorile cmpurilor de legtur, ceea ce determin urmtorul
rezultat:
Cod
Broker

Tabela Broker
Nume
Prenume
Broker
Broker

...

Cod
Client

...

Tabela Client
Nume
Cod
...
Client
Broker

...

Localitate
Client

Baze de date
189
189
189
189
211
211
211
211
533
533
533
533

Popescu
Popescu
Popescu
Popescu
Aldea
Aldea
Aldea
Aldea
Toma
Toma
Toma
Toma

Ion
Ion
Ion
Ion
Marina
Marina
Marina
Marina
Mircea
Mircea
Mircea
Mircea

100
300
500
600
100
300
500
600
100
300
500
600

31

Montana SA
Alpin SRL
MoldoTrans SA
Carpai SA
Montana SA
Alpin SRL
MoldoTrans SA
Carpai SA
Montana SA
Alpin SRL
MoldoTrans SA
Carpai SA

189
533
533
189
189
533
533
189
189
533
533
189

Braov
Braov
Iai
Braov
Braov
Braov
Iai
Braov
Braov
Braov
Iai
Braov

2. Clauza WHERE - Tuplurile tabelului rezultat prin produs cartezian sunt


filtrate, pe baza restriciei propriu-zise (LocalitateClient = Braov) i pe
baza condiiei de jonciune, care permite asocierea nregistrrilor
corespondente din cele dou tabele, prin raportarea la valorile atributelor
de legtur (Broker.CodBroker = Client.CodBroker). n consecin, se
obine urmtorul rezultat:
Cod
Broker
189
189
533

Tabela Broker
Nume
Prenume
Broker
Broker
Popescu Ion
Popescu Ion
Toma
Mircea

...

Cod
Client
100
600
300

...

Tabela Client
Nume
Cod
...
Client
Broker
Montana SA
189
Carpai SA
189
Alpin SRL
533

...

Localitate
Client
Braov
Braov
Braov

3. Instruciunea SELECT Este returnat rezultatul interogrii, afindu-se


realizrile anumitor cmpuri din tabelul Broker, dup eliminarea
duplicatelor (SELECT DISTINCT Broker.CodBroker, NumeBroker,
PrenumeBroker).
CodBroker
189
533

NumeBroker
Popescu
Toma

PrenumeBroker
Ion
Mircea

Dei mai rar utilizate dect compunerile interne, jonciunile externe sunt extrem
de utile la identificarea nregistrrilor dintr-o anumit tabel, care nu au
corespondent n alte tabele. Considerm urmtoarea cerin i fraza SQL asociat
ei:
S se afieze codurile, numele i prenumele brokerilor ce nu reprezint (nc) nici un
client.
SELECT Broker.CodBroker, NumeBroker, PrenumeBroker
FROM Broker LEFT JOIN Client
ON Broker.CodBroker = Client.CodBroker
WHERE Client.CodClient IS NULL ;

De aceast dat, rezultatul compunerii este un tabel ce conine toate nregistrrile


corespondente din cele dou tabele (cu alte cuvinte, rezultatul unei compuneri

32

Limbajul SQL

interne), la care se adaug tuplurile din tabela Broker, fr corespondent n tabela


Client. Plecnd de la premisa c tabele Broker i Client i pstreaz coninutul (a
se vedea exemplul referitor la compunerile interne), rezultatul jonciunii externe
este urmtorul :
Cod
Broker
189
189
211
533
533

Tabela Broker
Nume
Prenume
Broker
Broker
Popescu Ion
Popescu Ion
Aldea
Marina
Toma
Mircea
Toma
Mircea

...

Cod
Client
100
600
300
500

...

Tabela Client
Nume
Cod
...
Client
Broker
Montana SA
189
Carpai SA
189
Alpin SRL
MoldoTrans SA

533
533

...

Localitate
Client
Braov
Braov
Braov
Iai

Se poate observa c n cazul brokerilor fr clieni (aici, brokerul cu codul 211),


toate cmpurile provenite din tabela Client au valori nule. Aceast particularitate
este folosit n clauza WHERE, la definirea unui filtru care s rein tuplurile
tabelei Broker fr corespondent n Client (numite i nregistrri orfane), prin
impunerea condiiei de nulitate asupra oricruia din cmpurile tabelei Client (n
cazul de fa, s-a optat pentru Client.CodClient).
Exemple de compuneri privind tabelele generice A, B, C, definite n subcapitolul
3.2:

Fraz SQL
SELECT DISTINCT A.a1, a4, b2
FROM A INNER JOIN B ON A.a1 = B.a1
WHERE a4 >= (2 * b2)
ORDER BY b2 DESC ;
Echivalent cu:
SELECT DISTINCT A.a1, a4, b2
FROM A, B
WHERE A.a1 = B.a1 AND a4 > = (2 * b2)
ORDER BY b2 DESC ;
SELECT DISTINCT B.*
FROM B INNER JOIN C ON
(B.b1 = C.b1 AND B.b2 = C.b2)
WHERE c1 IN (B.b1, B.b2, a1) ;

Interpretare
Compunerea intern a tabelelor A i B, cu
reinerea nregistrrilor pentru care a4
reprezint cel puin dublul lui b2 i afiarea
cmpurilor a1, a4, b2. Rezultatele sunt sortate
descresctor dup b2 i sunt eliminate
duplicatele ce pot aprea la nivelul
cmpurilor afiabile (DISTINCT).
n al II-lea bloc de cerere, jonciunea intern
este obinut prin aplicarea produsului
cartezian ntre A i B i apoi a condiiei de
jonciune din clauza WHERE (A.a1 = B.a1).
Compunerea intern a tabelelor B i C, cu
reinerea nregistrrilor pentru care c1
coincide cu b1, b2, sau a1. Sunt eliminate
duplicatele ce pot aprea la nivelul atributelor

Baze de date
Echivalent cu:
SELECT DISTINCT B.*
FROM B, C
WHERE (B.b1 = C.b1 AND B.b2 = C.b2)
AND c1 IN (B.b1, B.b2, a1) ;
SELECT A.*
FROM A LEFT JOIN
(B LEFT JOIN C
ON (B.b1 = C.b1 AND B.b2 = C.b2))
ON A.a1 = B.a1
WHERE C.c1 IS NULL ;

33

vizibile (toate cmpurile tabelului B).

Sunt identificate nregistrrile din tabela A


fr corespondent n C, fiind reinute spre
afiare toate atributele din A.

Echivalent cu:
SELECT A.*
FROM C RIGHT JOIN
(B RIGHT JOIN A ON B.a1 = A.a1)
ON (C.b1 = B.b1 AND C.b2 = B.b2)
WHERE C.c1 IS NULL ;

Exemplificarea compunerilor
TranzaciiBursiere.accdb:

de

tabele,

la

nivelul

bazei

de

date

-1S se obin lista tranzaciilor de vnzare ncheiate la data curent, de ctre clienii din Iai,
Timioara i Braov.
SELECT Tranzacie.*, NumeClient
FROM Tranzacie INNER JOIN Client ON Tranzacie.CodClientVnztor = Client.CodClient
WHERE LocalitateClient IN (Iai, Timioara, Braov) AND DatTranzacie = DATE() ;
Echivalent cu:
SELECT Tranzaie.*, NumeClient
FROM Tranzacie, Client
WHERE Tranzacie.CodClientVnztor = Client.CodClient
AND LocalitateClient IN (Iai, Timioara, Braov) AND DatTranzacie = DATE() ;
-2S se identifice clienii care nu au ncheiat nicio tranzacie n calitate de cumprtori de titluri.
SELECT Client.*
FROM Tranzacie RIGHT JOIN Client ON Tranzacie.CodClientCumprtor = Client.CodClient
WHERE Tranzacie.NrTranzacie IS NULL ;
Echivalent cu:
SELECT Client.*
FROM Client LEFT JOIN Tranzacie ON Tranzacie.CodClientCumprtor = Client.CodClient
WHERE Tranzacie.NrTranzacie IS NULL ;
-3S se determine numrul total al tranzaciilor de vnzare efectuate de clienii din Iai, la data de
7 Martie 2007.
SELECT COUNT (*) AS NrTranzacii
FROM Tranzacie INNER JOIN Client ON Tranzacie.CodClientVnztor = Client.CodClient
WHERE LocalitateClient = Iai AND DatTranzacie = #7/3/2007# ;

34

Limbajul SQL

-4S se returneze lista tranzaciilor derulate n luna curent, ntre vnztori persoane fizice i
cumprtori persoane juridice.
SELECT Tranzacie.*
FROM Client AS Client1 INNER JOIN (Tranzacie INNER JOIN Client AS Client2
ON Tranzacie.CodClientCumprator = Client2.CodClient)
ON Client1.CodClient = Tranzacie.CodClientVnztor
WHERE MONTH(DatTranzacie) = MONTH(DATE())
AND YEAR(DatTranzacie) = YEAR(DATE())
AND Client1.TipClient = Persoan Fizic
AND Client2.TipClient = Persoan Juridic ;
Observaie: n acest caz, tabela Tranzacie trebuie compus de dou ori cu tabela Client, pentru a
obine att informaii privitoare la cumprtorii, ct i la vnztorii aciunilor (n cazul nostru,
aceste informaii se rezum la statutul juridic), care sunt evideniai n acelai tabel ( Client). ntr-o
astfel de situaie, ca s putem indica proveniena datelor (clientul vnztor sau cel cumprtor) am
fost nevoii s recurgem la dou nume distincte, Client1 i Client2, pentru a referi tabelul Client.
n concluzie, SQL permite utilizarea alias-urilor nu doar la nivel de cmp, ci i pentru redenumirea
tabelelor.
-5S se afieze numrul i valoarea total a cumprrilor de titluri (cu condiia ca aceast valoare
s fie de minim 100.000 RON) efectuate n anul precedent, la nivelul fiecrei localiti, cu
excepia Bucuretiului. Rezultatele vor fi ordonate descresctor, n funcie de numrul
tranzaciilor.
SELECT LocalitateClient, COUNT (*) AS NrVnzri,
SUM (NrAciuni * Valoare) AS ValoareVnzri
FROM Cotaie INNER JOIN (Tranzacie INNER JOIN Client
ON Tranzacie.CodClientCumprtor = Client.CodClient)
ON (Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Tranzacie.CodSocietate)
WHERE LocalitateClient < > Bucureti
AND YEAR(DatTranzacie) = YEAR (DATE()) - 1
GROUP BY LocalitateClient
HAVING SUM (NrAciuni * Valoare) > = 100000
ORDER BY COUNT (*) DESC ;
Observaie: Calcularea valorii tranzaciilor impune ca pentru titlurile cumprate s se identifice
cursul de la data ncheierii tranzaciei. Drept urmare, este necesar jonciunea tabelelor Cotaie i
Tranzactie, pe baza a dou criterii de compunere:
Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Tranzacie. CodSocietate

3.3.5 SUBINTEROGRI
O subinterogare (sau interogare imbricat), corespunde unui bloc de cerere, plasat
n interiorul unei alte fraze SQL, care valorific sub forma unor argumente,
rezultatul produs de subinterogare. Subinterogrile pot fi definite conform
urmtoarei sintaxe:

Baze de date

35

SELECT [domeniu_selecie] list_selecie


FROM {nume_tabel1 | list1_tabele}
WHERE
{cmp | expresie} operator_comparaie
( SELECT {cmp | expresie}
FROM {tabel1 | tabel2 | list2_tabele}
[WHERE
criterii_selecie_subinterogare] )
[AND criterii_selecie_interogare]

unde:
list_selecie = {*|nume_cmp[AS alias]|expresie[AS alias]}
[, ... n]
domeniu_selecie = {[ALL|DISTINCT|DISTINCTROW][TOP n [PERCENT]]}
operator_comparaie = { > | < | > = | < = | < > | = | IN | LIKE}

Observaii:
Dup cum reiese din sintaxa prezentat, o subinterogare i interogarea n
cadrul creia a fost definit pot avea la baz acelai tabel, sau surse de date
distincte. De asemenea, att interogarea principal, ct i subinterogarea, pot
necesita ca surse de date, tabele multiple (list_tabele) care, dup caz, trebuie
compuse prin jonciuni interne, sau externe.
Sintaxa prezentat aici are o form simplificat, ce poate fi extins prin
intermediul agregrilor i/sau sortrilor (GROUP BY, HAVING, ORDER BY),
att la nivelul interogrii principale, ct i al subinterogrii. n plus, este
posibil utilizarea unei suite de subinterogri, dispuse n cascad (SELECT n
SELECT n SELECT ...). Fiecare dintre aceste interogri, cu excepia blocului
de cerere plasat pe ultimul nivel de imbricare (care nu include o alt fraz
SQL), se bazeaz pe rezultatele returnate de subinterogrile pe care le
nglobeaz.
n cazul folosirii operatorului IN, rezultatul subinterogrii este n mod necesar
reprezentat de o list de valori sau, altfel spus, de un tabel mono-coloan. Toi
ceilali operatori impun ca subinterogarea s genereze ca rezultat o valoare
unic, al crei tip de date (Number, Text, Date, Logical etc.) trebuie s fie
compatibil cu tipul de date aferent celuilalt operand implicat n comparaie.
Raportndu-ne la aceast regul de sintax, putem evalua corectitudinea
urmtoarelor cereri SQL, definite pe baza tabelelor generice A i B, definite n
subcapitolul 3.2:
A ( a1, a2, a3, a4, a5, a6 )
B ( b1, b2, a1, b3 )
Fraz SQL

Interpretare

36

Limbajul SQL

SELECT * FROM A
WHERE a1 IN (SELECT a1 FROM B) ;

Corect. Subinterogarea genereaz un tabel cu un


singur atribut, printre ale crui realizri trebuie s se
regseasc cele ale cmpului a1 din tabela A.

SELECT * FROM A
WHERE a1 IN (SELECT * FROM B) ;

Incorect. Subinterogarea produce un tabel cu mai


multe coloane.

SELECT * FROM A
WHERE a1 >
(SELECT MAX (a1) FROM B) ;
SELECT * FROM A
WHERE a1 > (SELECT * FROM B) ;

Corect. Subinterogarea retuneaz o valoare unic,


cu care pot fi comparate realizrile cmpului A.a1.
Incorect. Subinterogarea produce un tabel.

Domeniul rezultatelor unei subinterogri poate fi influenat prin recurgerea la unul


din urmtoarele cuvintele cheie: ALL, SOME (sau echivalentul su, ANY) i
EXISTS. n cazul negaiilor, fiecare dintre specificatorii amintii va fi precedat de
NOT.
ALL i ANY/SOME sunt utilizai n cadrul unor expresii de comparaie, unul din
termenii comparaiei fiind reprezentat de setul de nregistrri returnat de o
subinterogare i constituit, n mod obligatoriu, dintr-o singur coloan. Rezultatul
comparaiilor depinde de natura specificatorului utilizat:

ANY/SOME Comparaia returneaz TRUE dac se verific pentru cel puin


una din valorile din coloana returnat de subinterogare.

ALL - Comparaia returneaz TRUE dac se verific pentru fiecare valoare


din coloana returnat de subinterogare. n mod uzual, comparaia const ntr-o
inegalitate: > | < | < = | > = | < > ALL (SELECT ). n cazul evalurii
egalitii, se verific dac cellalt termen al comparaiei (cmp / expresie)
coincide cu toate realizrile atributului returnat de subinterogare, ceea ce, de
regul, determin valoarea logic FALSE (TRUE constituie un rezultat de
excepie, obinut cnd subinterogarea returneaz o valoare unic, sau cnd
toate valorile returnate sunt identice).

EXISTS trateaz subinterogarea drept o condiie a crei valoare logic este


TRUE dac subinterogarea returneaz cel puin o nregistrare i FALSE, n caz
contrar. De remarcat c spre deosebire de ALL, ANY / SOME, specificatorul
EXISTS nu impune limite privind numrul cmpurilor returnate de o
subinterogare, acestea fiind practic irelevante: nu conteaz atributele
specificate prin instruciunea SELECT aferent subinterogrii (atributele
afiabile sunt indicate la nivelul interogrii principale), ci capacitatea acesteia
de a returna mcar o nregistrare.
innd cont de aceste precizri, putem evalua corectitudinea urmtoarelor cereri
SQL, definite pe baza acelorai tabele generice, A i B :
Fraz SQL

Interpretare

Baze de date

37

SELECT * FROM A
WHERE a1 > ALL (SELECT a1 FROM B) ;

Corect. Subinterogarea genereaz o list de


valori, provenite dintr-un tabel mono-coloan.
Interogarea principal returneaz nregistrrile
din tabela A pentru care valoarea atributului a1
este superioar tuturor valorilor produse de
subinterogare.

SELECT * FROM A
WHERE a1 = ANY (SELECT a1 FROM B) ;

Corect. Subinterogarea genereaz o list de


valori. Interogarea principal returneaz
nregistrrile tabelei A pentru care valoarea
atributului a1 coincide cu oricare din valorile
produse de subinterogare.

SELECT * FROM A
WHERE a1 < > ALL (SELECT * FROM B) ;

Incorect. Subinterogarea produce un tabel cu


mai multe coloane, motiv pentru care nu poate
fi asociat cu specificatorii ALL sau ANY
(SOME).
Corect sintactic, incorect din punct de vedere
logic. Vor fi returnate nregistrrile tabelei A
pentru care a1 este simultan egal cu toate
valorile returnate de subinterogare. Cu excepia
situaiei n care subinterogarea produce o
valoare unic, o atare condiie nu poate fi
verificat, interogarea principal returnnd zero
nregistrri.
Corect sintactic, incorect din punct de vedere
logic. La o prim vedere, o astfel de interogare
ar urma s returneze nregistrrile tabelei A, ce
au corespondent n tabela B. n realitate,
ntruct nu se stabilete nici o legtur ntre cele
dou tabele, EXISTS returneaz TRUE pentru
fiecare nregistrare din A, cu condiia ca tabela
B s conin mcar o nregistrare, i FALSE n
caz contrar. Drept consecin, interogarea
principal va genera dup caz, fie toate
nregistrrile tabelei A (cu sau fr legtur cu
cele din B), fie zero nregistrri.

SELECT * FROM A
WHERE a1 = ALL (SELECT a1 FROM B) ;

SELECT * FROM A
WHERE EXISTS
(SELECT * FROM B) ;

SELECT * FROM A
WHERE EXISTS
(SELECT * FROM B
WHERE A.a1 = B.a1) ;

Corect. Este redefinit interogarea de mai sus,


pentru a putea returna nregistrrile tabelei A, ce
au corespondent n B.

Echivalent cu:
SELECT * FROM A
WHERE a1 IN (SELECT a1 FROM B)

Exemplificarea subinterogrilor, pe baza tabelelor generice A, B i C:


A ( a1, a2, a3, a4, a5, a6 )
B ( b1, b2, a1, b3 )
C ( c1, b1, b2 )

38

Limbajul SQL

Fraz SQL
SELECT *
FROM A
WHERE a4 > = 2 * (SELECT a4
FROM A
WHERE a1 = 100) ;

Interpretare
Din tabela A, sunt returnate tuplurile
pentru care valoarea cmpului a4 este cel
puin dubl fa de valoarea aceluiai
cmp, n cazul n care a1 = 100.
Cererea este corect doar dac
subinterogarea returneaz o valoare unic
(a1 este cheie primar n tabela A, prin
urmare exist cel mult o nregistrare i
implicit o singur valoare a cmpului a4,
care satisface condiia a1 = 100)

SELECT *
FROM A
WHERE a1 IN (SELECT a1 FROM B
GROUP BY a1
HAVING SUM(b2) < 1000) ;
SELECT * FROM A
WHERE a4 > ALL (SELECT a4
FROM A
WHERE a5 > 100) ;

Sunt afiate nregistrrile tabelei A, pentru


care, la nivelul cmpului de legtur a1
din tabela B, totalul valorilor atributului
b2 este mai mic ca 1000.

SELECT *
FROM B
WHERE b2 = ANY (SELECT a5
FROM A
WHERE a5 IS NOT NULL) ;
SELECT A.*
FROM A
WHERE EXISTS (SELECT *
FROM B
WHERE A.a3 = B.b3) ;

Sunt afiate nregistrrile tabelei B, pentru


care valorile cmpului b2 aparin
domeniului reprezentat de realizrile
nenule ale atributului a5, din tabela A.

Din tabela A, sunt returnate tuplurile


pentru care atributul a4 are valori
superioare celor nregistrate n cazul n
care a5 > 100.

Sunt identificate nregistrrile tabelei A,


pentru care valorile cmpului a3 aparin
domeniului reprezentat de realizrile
atributului b3, din tabela B.

Exemple de interogri i subinterogri, definite


TranzaciiBursiere, prezentat n subcapitolul 3.1:

pe

baza

de

date

1
S se identifice brokerii care au i-au reprezentat clienii n tranzacii de vnzare, n luna
Martie a anilor 2005, 2006 i 2008.
SELECT * FROM Broker WHERE CodBroker IN (
SELECT CodBroker FROM Client WHERE CodClient IN (
SELECT CodClientVnztor
FROM Tranzacie
WHERE Month(DatTranzacie) = 3 AND
YEAR(DatTranzacie) IN (2005, 2006, 2008)
)) ;
Echivalent cu:

Baze de date

39

SELECT DISTINCT Broker.*


FROM Broker INNER JOIN (Client INNER JOIN Tranzacie
ON Client.CodClient = Tranzacie.CodClientVnztor)
ON Broker.CodBroker = Client.CodBroker
WHERE Month(DatTranzacie) = 3
AND YEAR(DatTranzacie) IN (2005, 2006, 2008) ;
2
S se afieze brokerii cu vechimea peste medie.
SELECT *, YEAR(DATE()) - YEAR(DatAngajare) AS Vechime
FROM Broker
WHERE (YEAR(DATE()) - YEAR(DatAngajare)) >
(SELECT AVG (YEAR(DATE()) - YEAR(DatAngajare))
FROM Broker) ;
3
S se identifice tranzaciile derulate la data de 1 Aprilie 2008, cu valoarea cuprins ntre
valorile aferente tranzaciilor 344 i 378.
SELECT *
FROM Tranzacie INNER JOIN Cotaie
ON (Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Tranzacie.CodSocietate)
WHERE DatTranzacie = #1/4/2008#
AND (NrAciuni * Valoare) BETWEEN
(SELECT (NrAciuni * Valoare)
FROM Tranzacie INNER JOIN Cotaie
ON (Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Tranzacie.CodSocietate)
WHERE NrTranzacie = 344)
AND (SELECT (NrAciuni * Valoare)
FROM Tranzacie INNER JOIN Cotaie ON
(Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Tranzacie.CodSocietate)
WHERE NrTranzacie = 378) ;
Observaie: ntruct valoarea unei tranzacii nu este disponibil sub forma unui atribut, ea trebuie
determinat att la nivelul interogrii principale, ct i la nivelul subinterogrilor care furnizeaz
limitele intervalului.
4
S identifice clienii care provin din aceleai localiti ca i societile care au emis titlurile ce
pot face obiectul tranzaciilor.
SELECT * FROM Client
WHERE LocalitateClient = ANY(SELECT LocalitateSocietate
FROM Societate) ;
Echivalent cu:
SELECT * FROM Client WHERE LocalitateClient IN
(SELECT LocalitateSocietate FROM Societate) ;
Echivalent cu:
SELECT DISTINCT Client.*
FROM Client INNER JOIN Societate

40

Limbajul SQL
ON Client.LocalitateClient = Societate.LocalitateSocietate ;

5
S identifice brokerii cu vechimea maxim.
SELECT * FROM BROKER
WHERE (YEAR(DATE()) - YEAR(DatAngajare)) >=
ALL (SELECT YEAR(DATE()) - YEAR(DatAngajare)
FROM Broker) ;
Echivalent cu:
SELECT * FROM BROKER
WHERE (YEAR(DATE()) - YEAR(DatAngajare)) =
(SELECT MAX (YEAR(DATE()) - YEAR(DatAngajare))
FROM Broker) ;
6
S identifice clienii care au efectuat i vnzri i cumprri de titluri n anul 2008.
SELECT * FROM Client
WHERE EXISTS (SELECT * FROM Tranzacie
WHERE YEAR(DatTranzacie) = 2008
AND CodClientCumprtor = Client.CodClient)
AND EXISTS (SELECT * FROM Tranzacie
WHERE YEAR(DatTranzacie) = 2008
AND CodClientVnztor = Client.CodClient) ;
Echivalent cu:
SELECT DISTINCT Client.*
FROM Client INNER JOIN Tranzacie
ON Client.CodClient= Tranzacie.CodClientCumprtor
WHERE YEAR(DatTranzacie) = 2008
AND EXISTS (SELECT * FROM Tranzacie
WHERE YEAR(DatTranzacie) = 2008
AND CodClientVnztor = Client.CodClient) ;

3.3.6 INTEROGRI UNION


Operatorul UNION permite gruparea unor interogri distincte i implicit,
combinarea ieirilor pe care acestea le genereaz, la nivelul unui set de rezultate
unic. Frazele SQL grupate prin UNION corespund unor cereri de consultare a
datelor care genereaz tabele identice ca structur (acelai numr de atribute,
aceeai succesiune a tipurilor de date aferente cmpurilor), dar care pot s difere
sub aspectul complexitii: de la cele mai simple (SELECT ... FROM), pn la
cele care recurg la mai multe tabele-surs, subinterogri, agregri, restricii etc.
ntr-o form simplificat, sintaxa interogrilor de acest tip este urmtoarea:
SELECT [domeniu_selecie1] list_selecie1
FROM tabel1
[WHERE list_criterii_selecie1]
UNION

[ALL]

Baze de date

41

SELECT [domeniu_selecie2] list_selecie2


FROM tabel2
[WHERE list_criterii_selecie2]
[UNION [ALL]
SELECT ]
[ORDER BY list_criterii_sortare [sens_sortare] ] ;

unde:

domeniu_selecie = {ALL|DISTINCT|DISTINCTROW} [TOP n [PERCENT]]


list_selecie = { *|nume_cmp [AS alias] | expresie
AS alias] } [, ... n]
sens_sortare = {ASC | DESC}

Cnd se folosete specificatorul ALL, tabelul rezultat grupeaz toate tuplurile


(inclusiv pe cele care se repet) generate de fiecare instruciune SELECT, n timp
ce absena sa determin eliminarea duplicatelor, fiecare nregistrare fiind afiat o
singur dat. Spre deosebire de DISTINCT, care opereaz la nivelul unui bloc de
cerere individual, atunci cnd nu este nsoit de ALL, UNION permite eliminarea
duplicatelor ce pot rezulta n urma combinrii nregistrrilor generate de
interogrile individuale. Dac se urmrete ordonarea tuplurilor, criteriile de
sortare vor fi specificate o singur dat, printr-o clauz ORDER BY final, ce
opereaz la nivelul ntregului set de rezultate.
Spre exemplificare, considerm o interogare definit pe tabelele Client i
Tranzacie, din baza de date TranzaciiBursiere.accdb:
S afieze toi clienii (cod, tip client, nume) care au participat la tranzacii, indiferent de calitatea n
care au acionat (vnztori i/sau cumprtori de titluri); sortare ascendent, dup tipul i numele
clienilor.
SELECT Client.CodClient, TipClient, NumeClient
FROM Client INNER JOIN Tranzacie
ON Client.CodClient = Tranzacie.CodClientVnztor
UNION
SELECT Client.CodClient, TipClient, NumeClient
FROM Client INNER JOIN Tranzacie
ON Client.CodClient = Tranzacie.CodClientCumprtor
ORDER BY TipClient, NumeClient ;
Tabela Client

Tabela Tranzacie

42

Limbajul SQL

n fraza SQL prezentat mai sus, operatorul UNION permite alipirea rezultatelor a
dou interogri distincte, dintre care, prima returneaz clienii care au vndut
titluri, iar cea de-a doua, clienii care au achiziionat aciuni. ntruct acelai client
poate participa la mai multe tranzacii, fiecare dintre aceste interogri poate
genera duplicate la nivelul cmpurilor afiabile (CodClient, TipClient,
NumeClient); mai mult, duplicatele pot rezulta i din alipirea rezultatelor produse
de cele dou cereri de selecie, deoarece este posibil ca anumii clieni s fi avut i
calitatea de vnztori i de cumprtori (nu n cadrul aceleiai tranzacii). Pentru a
combina rezultatele produse de cele dou interogri, eliminnd totodat
duplicatele, indiferent de sursa lor, s-a folosit operatorul UNION fr
specificatorul ALL, astfel nct fiecare client va fi afiat o singur dat.
n continuare sunt redate rezultatele compunerii tabelelor Client i Tranzacie,
pentru identificarea:
- Clienilor care au vndut titluri:
Client.CodClient = Tranzacie.CodClientVnztor
Tabela Client
Cod
Client
100
100
300
500

TipClient
Persoan Juridic
Persoan Juridic
Persoan Fizic
Persoan Juridic

Nume
Client
Montana SA
Montana SA
Popa Ana
Bucovina SA

...

Nr
Tranzacie
556
700
777
802

Tabela Tranzacie
CodClient
CodClient
Vnztor Cumprtor
100
300
100
500
300
500
500
100

...

i a celor care au cumprat aciuni:


Client.CodClient = Tranzacie.CodClientCumprtor
Tabela Client

Cod
Client
300
500
500
100

TipClient
Persoan Fizic
Persoan Juridic
Persoan Juridic
Persoan Juridic

Nume
Client
Popa Ana
Bucovina SA
Bucovina SA
Montana SA

...

Nr
Tranzacie
556
700
777
802

Tabela Tranzacie
CodClient
CodClient
Vnztor Cumprtor
100
300
100
500
300
500
500
100

...

n condiiile n care ambele interogri rein spre afiare atributele CodClient,


TipClient i NumeClient, rezultatul aplicrii operatorului UNION pentru reunirea
celor dou seturi de nregistrri i al clauzei ORDER BY, pentru sortarea datelor
n funcie de tipul, respectiv numele clienilor, este urmtorul:
CodClient

TipClient

NumeClient

Baze de date
300
500
100

Persoan Fizic
Persoan Juridic
Persoan Juridic

43
Popa Ana
Bucovina SA
Montana SA

Exemplificarea interogrilor UNION, pe baza tabelelor generice A i B, definite n


subcapitolul 3.2:
A (a1, a2, a3, a4, a5, a6)
B (b1, b2, a1, b3)
Fraz SQL
SELECT a3 FROM A
UNION
SELECT b3 FROM B
ORDER BY 1 DESC ;
SELECT AVG (a4) AS Medie
FROM
(SELECT a4 FROM A
UNION
SELECT a5 FROM A) ;

Interpretare
Este obinut o list a datelor calendaristice din
cmpurile a3 i b3, fiecare valoare fiind preluat o
singur dat; datele sunt sortate descendent.
Este determinat media tuturor valorilor din cmpurile
a4 i a5. nainte de calculul propriu-zis, valorile sunt
reunite n cadrul unei coloane unice, asupra creia se
poate aplica funcia AVG.

Interogri UNION definite pe baza de date TranzaciiBursiere, prezentat n


subcapitolul 3.1:
1
S identifice brokerii care au intermediat tranzacii n anul 2008.
SELECT * FROM Broker
WHERE CodBroker IN
(SELECT CodBroker FROM Tranzacie INNER JOIN Client
ON Tranzacie.CodClientVnztor = Client.CodClient)
WHERE YEAR(DatTranzacie) = 2008
UNION
SELECT CodBroker FROM Tranzacie INNER JOIN Client
ON Tranzacie.CodClientCumprtor = Client.CodClient)
WHERE YEAR(DatTranzacie) = 2008) ;
S afieze tranzaciile de la data curent, efectuate de persoanele fizice, n calitate de
cumprtori, precum i cele ncheiate de persoanele juridice, n calitate de vnztori.
SELECT Tranzacie.*
FROM Tranzacie INNER JOIN Client
ON Tranzacie.CodClientCumprator = Client.CodClient
WHERE DatTranzacie = DATE () AND TipClient = Persoan Fizic
UNION
SELECT Tranzacie.*
FROM Tranzacie INNER JOIN Client
ON Tranzacie.CodClientVnztor = Client.CodClient
WHERE DatTranzacie = DATE ()
AND TipClient = Persoan Juridic ;

3.3.7 Interogri parametrizate

44

Limbajul SQL

Interogrile de acest tip permit ca specificarea anumitor argumente de la nivelul


clauzelor SQL s poat fi realizat prin recurgerea la parametrii a cror valoare
poate fi schimbat la fiecare execuie a interogrii, ceea ce face ca blocul de cerere
s fie uor adaptabil la necesitile utilizatorilor. Exist dou modaliti de
specificare a parametrilor:
Explicit nainte de a fi utilizai n mod efectiv, parametrii sunt definii
printr-o declaraie ce preced interogarea propriu-zis:
PARAMETERS
Nume_parametru Tip_dat [, ... n] ;
SELECT ... (interogarea care folosete parametrii declarai n
prealabil) ;

Implicit Parametrii sunt utilizai n mod direct n interogare, fr a fi


declarai anterior: cu excepia valorilor text, ncadrate de ghilimele, orice text
ce nu coincide cu numele unui cmp din tabelele surs este n mod automat
asimilat unui parametru; ca i n cazul cmpurilor i tabelelor, numele de
parametrii care includ spaii trebuie delimitate prin paranteze drepte [ ].

Exemplificarea interogrilor parametrizate, pe baza tabelelor generice A i B,


definite n subcapitolul 3.2:
A (a1, a2, a3, a4, a5, a6)
B (b1, b2, a1, b3)
Fraz SQL
SELECT a2, SUM(a3) AS Total FROM A
GROUP BY a2
HAVING SUM(a3) BETWEEN
[Limita inferioar] AND [Limita superioar] ;

Interpretare
Folosind tabela A, se nsumeaz valorile
cmpului a4, la nivelul realizrilor distincte ale
atributului a2, returnndu-se doar sumele
cuprinse ntre dou limite specificate ca
parametrii.

PARAMETERS [Reper numeric] Integer,


[Reper dat] Date ;
SELECT DISTINCT a1, a2, a4
FROM A INNER JOIN B ON A.a1 = B.a1
WHERE b3 = [Reper dat]
AND b2 > [Reper numeric] ;

Sunt identificate nregistrrile tabelului A ce au


drept corespondent, n tabelul B, tupluri n care
b2 (de tip Integer) are o valoare superioar unui
prag specificat ca parametru, iar b3 (de tip Date)
coincide cu valoarea unui al doilea parametru. Se
afieaz realizrile cmpurilor a1, a2 i a4,
eliminndu-se duplicatele ce pot rezulta n urma
compunerii tabelelor A i B.

Interogri parametrizate definite pe baza de date TranzaciiBursiere, prezentat n


subcapitolul 3.1:
1
S se afieze societile cu valoarea capitalului social superioar unui prag indicat ca
parametru.

Baze de date

45

SELECT *, (NrAciuniEmise * ValoareNominal) AS CapitalSocial


FROM Societate
WHERE (NrAciuniEmise * ValoareNominal) > [Introducei limita] ;
Observaie: Anterior interogrii, parametrul poate fi declarat explicit:
PARAMETERS [Introducei limita] Number ;
2
S se afieze tranzaciile ncheiate, n condiiile n care perioada n care acestea s-au efectuat i
statutul juridic al participanilor sunt specificate ca parametri.
SELECT Tranzacie.* FROM Tranzacie
WHERE DatTranzacie BETWEEN [Debut interval]
AND [Sfrit interval]
AND CodClientVnztor = ANY
(SELECT CodClient FROM Client
WHERE TipClient = [Tip client vnztor])
AND CodClientCumprtor = ANY
(SELECT CodClient FROM Client
WHERE TipClient = [Tip client cumprtor]) ;
Observaie: Anterior interogrii, parametrii pot fi declarai explicit:
PARAMETERS [Debut interval] Date, [Sfrit interval] Date,
[Tip client vnztor] Text (20),
[Tip client cumprtor] Text (20) ;
3
S se determine numrul i valoarea total a tranzaciilor care vizeaz societile dintr-o
localitate ce se precizeaz la momentul execuiei interogrii.
SELECT COUNT(*) AS NrTranzacii,
SUM (NrAciuni*Valoare) AS TotalValoric
FROM Societate INNER JOIN
(Tranzacie INNER JOIN Cotaie
ON Tranzacie.DatTranzacie = Cotaie.DatCotaie
AND Tranzacie.CodSocietate = Cotaie.CodSocietate)
ON Societate.CodSocietate = Tranzacie.CodSocietate
WHERE LocalitateSocietate = [Introducei localitatea] ;
Observaie: Anterior interogrii, parametrul poate fi declarat explicit:
PARAMETERS [Introducei localitatea] Text (30) ;

3.3.8 Interogri CROSSTAB


CROSSTAB desemneaz un tip particular de interogri, care permit centralizarea
datelor din tabelele-surs, rezultatele fiind returnate sub forma unui alt tabel, cu
dubl intrare: valorile cmpurilor / expresiilor folosite drept criterii de agregare
sunt afiate ca antete de rnduri i coloane, iar valorile agregat sunt dispuse n
celulele tabelului, la intersecia rndurilor cu coloanele. Sintaxa interogrilor
CROSSTAB este urmtoarea:

46

Limbajul SQL

TRANSFORM valoare_agregat
SELECT list_selecie
FROM list_tabele
[WHERE
list_criterii_selecie_preagregare]
GROUP BY list_criterii_grupare
ORDER BY list_criterii_sortare
PIVOT {cmp_pivot | expresie_pivot} ;

Observaii:
- list_tabele indic tabela sau tabelele pe care este definit interogarea. n
mod evident, dac se recurge la mai multe tabele-surs, se impune
compunerea acestora prin jonciuni interne sau, dup caz, externe.
- O interogare crosstab se obine prin adugarea instruciunii TRANSFORM
i a clauzei PIVOT, naintea, respectiv la sfritul unei cereri tipice de
consultare a datelor, care trebuie ns s includ clauza GROUP BY. Drept
urmare, SELECT, FROM, WHERE, GROUP BY i ORDER BY au
aceeai semnificaie i se supun regulilor specifice cererilor de centralizare
a datelor prezentate pn n acest moment (a se revedea subcapitolul
3.3.3). Exist ns dou diferene semnificative:
- Dup cum se observ din sintax, interogrile crosstab nu admit
clauza HAVING, restriciile putnd fi specificate doar prin
intermediul clauzei WHERE; drept urmare, nu pot fi impuse
condiii asupra valorilor-agregat (de exemplu, SUM(nume_cmp) >
100).
- list_selecie nu poate include valori agregate, ci doar criterii de
grupare. n plus, n tabelul rezultat n urma interogrii, valorile
cmpurilor/expresiilor din list_selecie furnizeaz antetele
aferente rndurilor.
- cmp|expresie_pivot - Desemneaz un singur cmp (expresie) ale crui
realizri constituie criterii de agregare a datelor (alturi de valorile
cmpurilor i/sau expresiilor din list_criterii_grupare) i n acelai timp,
antete aferente coloanelor din tabelul generat de interogare.
- valoare_agregat = {AVG | COUNT | MAX
| MIN | SUM ({nume_cmp | expresie})}[AS
alias]
Indic un singur atribut (expresie) ale crui valori face obiectul
centralizrii, prin aplicarea unei singure funcii totalizatoare. Valorile-

Baze de date

47

agregat obinute vor fi dispuse la intersecia dintre rndurile i coloanele


tabelului cu dubl intrare, rezultat n urma interogrii.
Pentru exemplificare, vom considera o cerin care vizeaz baza de date
TranzaciiBursiere, prezentat n subcapitolul 3.1 i care poate fi soluionat prin
dou blocuri SQL distincte:
La nivelul localitilor n care sunt amplasate societile ale cror titluri au fost tranzacionate,
s se determine numrul tranzaciilor ncheiate lunar, n anii 2007 i 2008.
Varianta 1 (CROSSTAB):
TRANSFORM COUNT (*) AS NrTranzacii
SELECT YEAR(DatTranzacie) AS An, MONTH(DatTranzacie) AS Lun
FROM Tranzacie INNER JOIN Societate
ON Tranzacie.CodSocietate = Societate.CodSocietate
WHERE YEAR(DatTranzacie) IN (2007, 2008)
GROUP BY YEAR(DatTranzacie), MONTH(DatTranzacie)
PIVOT LocalitateSocietate ;
Varianta 2 (non-CROSSTAB):
SELECT YEAR(DatTranzacie) AS An, MONTH(DatTranzacie) AS Lun,
LocalitateSocietate, COUNT (*) AS NrTranzacii
FROM Tranzacie INNER JOIN Societate
ON Tranzacie.CodSocietate = Societate.CodSocietate
WHERE YEAR(DatTranzacie) IN (2007, 2008)
GROUP BY YEAR(DatTranzacie), MONTH(DatTranzacie),
LocalitateSocietate ;

Presupunem c tabelele Societate, respectiv Tranzacie, au urmtorul coninut:


Tabela Societate

Tabela Tranzacie

48

Limbajul SQL

n cazul ambelor fraze SQL, compunerea celor dou tabele, urmat de aplicarea
clauzei WHERE (eliminarea tranzaciilor care nu s-au ncheiat n 2007 sau 2008),
produce urmtorul rezultat:
Nr
Tranzacie
121
300
301
802
803
809
812
850

Tabela Tranzacie
Cod
...
Societate
222
333
111
111
333
444
444
111

Data
Tranzacie
01-08-2007
06-11-2007
06-11-2007
11-11-2008
12-11-2008
20-11-2008
25-11-2008
01-12-2008

...

Cod
Societate
222
333
111
111
333
444
444
111

Tabela Societate
Localitate
Denumire
Societate
Zodiac
Bucureti
Rustic
Timioara
Banatul
Timioara
Banatul
Timioara
Rustic
Timioara
Dunrea
Constana
Dunrea
Constana
Banatul
Timioara

...

Dei provin din acelai set de nregistrri i conin date identice, tabelele generate
de cele dou blocuri SQL se deosebesc prin maniera de prezentare a acestor date:
An
Lun LocalitateSocietate NrTranzacii
2007
8 Bucureti
1
2007
11 Timioara
2
2008
11 Constana
2
2008
11 Timioara
2
2008
12 Timioara
1
Rezultatul interogrii n variant non-CROSSTAB
An
Lun Bucureti Constana Timioara
2007
8
1
2007
11
2
2008
11
2
2
2008
12
1
Rezultatul interogrii n variant CROSSTAB

ntruct genereaz un tabel cu dubl intrare, o interogare crosstab necesit minim


dou criterii de agregare, dintre care unul singur, desemnat prin clauza PIVOT, va
furniza antele coloanelor, iar toate celelalte, desemnate prin GROUP BY, respectiv
SELECT, vor furniza antetele rndurilor. n exemplul prezentat, datorit faptului
c, din punct de vedere conceptual, anii i lunile desemneaz criterii de agregare
de acelai tip (repere temporale), acestea au fost utilizate mpreun, ca antete de
rnduri, n timp ce localitile, care corespund unor criterii de alt natur (repere
geografice) au fost desemnate antete de coloane.
n cazul unor agregri multiple (spre exemplu, alturi de numrul tranzaciilor ar
trebui s afim i valoarea acestora), sau al restriciilor ce vizeaz valorileagregat (s presupunem c ne intereseaz doar lunile cu cel puin 3 tranzacii) i
care nu pot fi specificate dect prin clauza HAVING, crosstab nu mai reprezint o
opiune, unica soluie fiind reprezentat de o cerere tipic de consultare a datelor,
care recurge la grupri i centralizri.

Baze de date

49

Exemplificarea interogrilor crosstab, pe baza tabelelor generice A i B, definite


n subcapitolul 3.2:
A (a1, a2, a3, a4, a5, a6)
B (b1, b2, a1, b3)
Fraz SQL
TRANSFORM SUM (a6)
SELECT a2, a3
FROM A
WHERE a6 NOT IN (a4, a5)
GROUP BY a2, a3
PIVOT a5 ;
TRANSFORM AVG (b2)
SELECT a1
FROM A INNER JOIN B ON A.a1 = B.a1
WHERE b3 > a3
GROUP BY a1
PIVOT a2 ;

Interpretare
Pe baza tabelului A, pentru fiecare valoare
distinct a atributelor a2, a3 i a5, sunt nsumate
valorile din a6, care difer de cele din a4 i a5.

Pe baza tabelelor A i B, pentru fiecare valoare


distinct a atributelor a1 i a2, este determinat
media valorilor cmpului b2, n situaia n care
valorile din b3 sunt superioare celor din a3.

Interogri crosstab definite pe baza de date TranzaciiBursiere, prezentat n


subcapitolul 3.1:
1
Pentru societatea cu codul S5, s se determine numrul aciunilor tranzacionate n fiecare lun a
ultimilor 3 ani.
TRANSFORM SUM(NrAciuni) AS NrTotalAciuni
SELECT MONTH(DatTranzacie) AS Lun
FROM Tranzacie
WHERE YEAR(DatTranzacie) > = (YEAR(DATE()) - 3) AND CodSocietate = S5
GROUP BY MONTH(DatTranzacie)
PIVOT YEAR(DatTranzacie) ;
2
S se calculeze valoarea medie lunar a vnzrilor de titluri efectuate n anul curent, pe categorii de
clieni (PF/PJ) i pe localiti de provenien a clienilor vnztori.
TRANSFORM AVG (NrAciuni * Valoare) AS ValoareMedie
SELECT TipClient, LocalitateClient
FROM Cotaie INNER JOIN (Tranzacie INNER JOIN Client
ON Tranzacie.CodClientVnztor = Client.CodClient)
ON (Cotaie.DatCotaie = Tranzacie.DatTranzacie
AND Cotaie.CodSocietate = Societate.CodSocietate)
WHERE YEAR(DatTranzacie) = YEAR(DATE())
GROUP BY TipClient, LocalitateClient
PIVOT MONTH(DatTranzacie) ;

3.4. Interogri pentru actualizarea datelor


Actualizarea datelor se realizeaz printr-o categorie distinct de cereri SQL,
cunoscute drept interogri de aciune, care, n funcie de specificul lor, vizeaz
operaii de tipul crerii de tabele, adugrii, tergerii, respectiv modificrii
nregistrrilor stocate n tabele.

50

Limbajul SQL

3.4.1 Crearea tabelelor


Un bloc de cerere de acest tip are la baz o fraz SQL definit n scopul
consultrii datelor i se conformeaz urmtoarei sintaxe:
SELECT [domeniu_selecie] list_selecie
INTO nume_tabel_nou
FROM nume_tabel_surs
[WHERE list_criterii_selecie] ;

unde:

domeniu_selecie = {ALL|DISTINCT|DISTINCTROW}[TOP n [PERCENT]]


list_selecie = { * |nume_cmp [AS alias] | expresie
[AS alias] } [, ... n]

O astfel de cerere permite ca setul de nregistrri returnat de orice interogare a


bazei de date s poat fi memorat n forma unui tabel distinct
(nume_tabel_nou). Din intenia de a accentua specificul cererilor de creare a
tabelelor, am prezentat forma minimal a sintaxei. Facem ns precizarea c orice
cerere de consultare a datelor (cu una sau mai multe tabele surs, cu sau fr
centralizri, restricii, sortri etc.), creia i se adaug clauza INTO..., poate fi
transformat ntr-o cerere de creare a unui nou tabel, crui i furnizeaz structura
i nregistrrile iniiale.
Exemple de creare a unor noi tabele, pe baza unor cereri de consultare a tabelului
generic A, definit n subcapitolul 3.2:
A ( a1, a2, a3, a4, a5, a6 )
Fraz SQL
SELECT a1, a2, (a5 + a4) AS Suma
INTO Tabel1
FROM A
WHERE a3 IS NOT NULL
ORDER BY (a5+a4) DESC ;

Interpretare
Se adaug ntr-un nou tabel (Tabel1), nregistrrile
tabelului A, cu valori nenule n cmpul a3,
reinndu-se spre afiare cmpurile a1, a2 i expresia
a5 + a4. nregistrrile vor fi ordonate descresctor,
dup rezultatele expresiei a5 + a4.

SELECT a1, a3, a4


INTO Tabel2
FROM A
WHERE a4 > ALL (SELECT a5
FROM A
WHERE a2 = [Reper a2]) ;

Se creeaz tabelul Tabel2 i se adaug n acesta toate


nregistrrile tabelului A, n care valoarea lui a4 este
mai mare dect toate valorile lui a5, nregistrate
atunci cnd a2 este egal cu un anumit reper, furnizat
ca parametru. Cmpurile reinute pentru a fi incluse
n tabelul nou creat sunt a1, a3 i a4.

Crearea de noi tabele prin cereri definite pe baza de date TranzaciiBursiere,


prezentat n subcapitolul 3.1:
1

Baze de date

51

S se creeze un tabel numit ListClieni cu atributele CodClient, NumeClient i TipClient, care


s conin date aferente clienilor persoane juridice, al cror nume este compus din 6 caractere
i ncepe cu literele A, F sau M.
SELECT CodClient, NumeClient, TipClient
INTO ListClieni
FROM Client
WHERE TipClient = Persoan Juridic
AND NumeClient LIKE [A, F, M]????? ;
Observaie: innd cont de semnificaia celor dou caratere de nlocuire (? substituie un singur
caracter, * substituie 0-n caractere), restricia privitoare la nume poate fi exprimat i n forma:
NumeClient LIKE A????? OR
NumeClient LIKE F????? OR
NumeClient LIKE M?????
De asemenea, se poate folosi funcia LEN, care returnez lungimea unui text:
NumeClient LIKE [A,F,M]* AND LEN(NumeClient) = 6
2
S se creeze un tabel numit ListSocieti, care s conin datele aferente societilor din
Bucureti i Iai, cu ncadrarea acestora, n funcie de mrimea capitalului social, n
urmtoarele categorii: societate de mici dimensiuni (capital sub 50.000 RON), societate medie
(capital ntre 50.000 i 100.000 RON), societate de mari dimensiuni (capital de peste 100.000
RON).
SELECT *,
IIF ((NrAciuniEmise * ValoareNominal) < 50000,
societate mic,
IIF ((NrAciuniEmise * ValoareNominal) < 100000,
societate medie, societate mare))
AS CategorieSocietate
INTO ListSocieti
FROM Societate
WHERE LocalitateSocietate IN (Bucureti, Iai) ;
Observaie: Pentru determinarea categoriei de societate s-a recurs la funcii IIF, imbricate: dac
nivelul capitalului social este mai mic de 50.000 RON, se obine societate mic, n caz contrar
fiind necesar un alt test privind valoarea capitalului, adic o alt funcie IIF, care va returna, dup
caz, societate medie, sau societate mare. Se poate observa c n cazul celui de-al II-lea test nu
este nevoie s se specifice limita inferioar a intervalului, aceasta fiind, n mod implicit, 50.000 (a
doua condiie nu este evaluat dect dac prima a returnat valoarea logic FALSE, adic atunci
cnd capitalul social este mai mare sau egal cu 50.000 RON).

3.4.2 Adugarea de nregistrri n tabele


Sintaxa cererilor SQL pentru adugarea de tupluri se prezint sub dou forme:
Sintaxa I
INSERT INTO nume_tabel_destinaie [(nume_cmp1, nume_cmp2, ...)]
VALUES (valoare1, valoare2, ...) ;

52

Limbajul SQL

n acest caz, n tabela menionat se adugat o singur nregistrare, constituit


din valorile enumerate; fiecrui element din lista de valori i corespunde cmpuldestinaie aflat pe poziia similar, n cadrul listei de cmpuri.
Sintaxa II
INSERT INTO nume_tabel_destinaie [(nume_cmp1, nume_cmp2, ...)]
SELECT [domeniu_selecie] list_selecie
FROM nume_tabel_surs
[WHERE list_criterii_selecie] ;

unde:

domeniu_selecie = {ALL|DISTINCT|DISTINCTROW}[TOP n [PERCENT]]


list_selecie = { * |nume_cmp [AS alias] | expresie
[AS alias] } [, ... n]

n tabela-destinaie va fi adugat setul de nregistrri returnat de cererea de


selecie. ntruct, pentru simplificare, am ales s prezentm forma minimal a
sintaxei, facem precizarea c orice cerere de consultare a datelor (cu una sau mai
multe tabele surs, cu sau fr centralizri, restricii etc.), precedat de
instruciunea INSERT INTO... poate fi transformat ntr-o cerere de adugare de
nregistrri.
Dup cum se observ din cele dou sintaxe generice, specificarea cmpurilordestinaie este opional. Cnd acestea sunt omise, n mod implicit, se consider
c vor fi completate, n ordine, de la primul spre ultimul, toate cmpurile tabeleidestinaie. De asemenea, atunci cnd se furnizeaz lista de cmpurilor-destinaie,
dar aceasta nu cuprinde toate atributele tabelei n care vor fi adugate datele, n
noile nregistrri, cmpurile ce nu sunt explicit enumerate vor fi setate automat la
valoarea implicit, sau n absena acesteia, la NULL.
Indiferent de sintaxa utilizat, numrul atributelor-destinaie (instruciunea
INSERT INTO) trebuie s coincid cel al valorilor din clauza VALUES, respectiv
al cmpurilor/expresiilor specificate prin instruciunea SELECT. n plus, tipul de
date aferent unui anumit cmp-destinaie trebuie s fie compatibil cu cel al
elementului aflat pe poziia similar n cadrul listei de valori (VALUES), sau de
cmpuri (SELECT).
Exemple de cereri de adugare de nregistrri, bazate pe tabelele generice A i
Tabel1 (obinut printr-o cerere SQL de creare a unui nou tabel - a se vedea
seciunea anterioar):
A ( a1, a2, a3, a4, a5, a6 )
Tabel1(a1, a2, Suma)
Bloc de cerere SQL
INSERT INTO Tabel1 (a1, a2)
VALUES (100, 200) ;

Interpretare
Se adaug o nou nregistrare n Tabel1, fr a se
furniza o valoare pentru cmpul Suma (e
considerat NULL).

Baze de date

53

INSERT INTO Tabel1 (a1, a2)


SELECT a1, a2
FROM A
WHERE a1 NOT IN
(SELECT a1 FROM Tabel1) ;

Tot n Tabel1, n cmpurile a1 i a2, se adaug


realizrile aferente atributelor a1, respectiv a2,
din tabela A, reinndu-se nregistrrile pentru
care valorile lui a1 nu se regsesc deja printre
cele ale atributului a1 din Tabel1.

INSERT INTO Tabel1 (a1, a2)


SELECT *
FROM A
WHERE a1 < > ALL
(SELECT a1 FROM Tabel1) ;

Incorect. Teoretic, se urmrete acelai lucru ca


i prin interogarea precedent, avnd n vedere c
blocurile SELECT sunt echivalente. Problema
este determinat de diferena dintre numrul
cmpurilor- surs (3), din tabela A i cel al
cmpurilor-destinaie (2), din Tabel1.

Cereri de adugare de tupluri, definite la nivelul bazei de date TranzaciiBursiere,


prezentat n subcapitolul 3.1:
1
S se insereze n tabela ListClieni (adugat n seciunea anterioar, prin cerere de creare de
tabel) datele aferente persoanelor fizice din localiti al cror nume debuteaz cu o liter din
intervalul D-M. Vor fi exceptai clienii al cror nume ncep cu litere cuprinse ntre C i M.
INSERT INTO ListClieni
SELECT CodClient, NumeClient, TipClient
FROM Client
WHERE TipClient = Persoan Juridic
AND LocalitateClient LIKE [D-M]*
AND NumeClient LIKE [!C-M]* ;
Observaii:
- ntruct a fost omis lista cmpurilor-destinaie, este necesar ca instruciunea SELECT s furnizeze
valori pentru fiecare dintre atributele tabelului ListClieni, ntr-o anumit succesiune, determinat
de modul n care sunt ordonate cmpurile n acest tabel.
- Restricia privitoare la numele clienilor poate fi specificat i sub forma: NumeClient NOT LIKE
[C-M]*.
2
S se insereze n tabela ListSocieti (adaugat n seciunea anterioar, prin cerere de creare de
tabel), date privind societile ale cror titluri nu au fcut obiectul tranzaciilor n anul curent i
care nu sunt deja evideniate n acest tabel. Completarea cmpului CategorieSocietate, se va
realiza dup regula folosit la crearea tabelului.
INSERT INTO ListSocieti
SELECT *, IIF (NrAciuniEmise * ValoareNominal < 50000,
societate mic,
IIF (NrAciuniEmise * ValoareNominal < 100000,
societate medie, societate mare))
FROM Societate
WHERE CodSocietate < > ALL (SELECT CodSocietate
FROM ListSocieti)
AND CodSocietate NOT IN (
SELECT CodSocietate
FROM Tranzacie

54

Limbajul SQL
WHERE YEAR(DatTranzacie) = YEAR(DATE())
);

3.4.3 tergerea nregistrrilor din tabele


O cerere SQL privind tergerea de nregistrri permite ca dintr-o tabel specificat
s fie eliminate tuplurile ce se conformeaz unui set de criterii, sau, n absena
acestora, toate nregistrrile. Sintaxa generic a cererilor de acest tip este
urmtoarea:
DELETE *
FROM nume_tabel
[WHERE list_criterii_tergere] ;

Exemple bazate pe tabelele generice A i C, definite n subcapitolul 3.2:


A ( a1, a2, a3, a4, a5, a6 )
C ( c1, b1, b2 )
Fraz SQL
DELETE * FROM C ;

Interpretare
Sunt terse toate nregistrrile din tabela C.

DELETE * FROM A
WHERE a3 NOT BETWEEN
[Limita1] AND [Limita2] ;

Sunt terse toate nregistrrile tabelei A, pentru


care valoarea cmpului a3 se situeaz n afara
unui interval specificat prin parametrii.

DELETE * FROM A
WHERE a3 = (SELECT MIN(a3) FROM A) ;

Sunt terse toate nregistrrile din tabela A, n


cazul crora, atributul a3 are valoarea minim.

Cereri SQL privind tergerea de nregistrri, definite pe baza de date


TranzaciiBursiere, prezentat n subcapitolul 3.1:
1
S se elimine din baza de date societile ale cror titluri nu au fcut obiectul nici unei
tranzacii n anul precedent.
DELETE * FROM Societate
WHERE CodSocietate = ANY (
SELECT CodSocietate FROM Tranzacie
WHERE YEAR(DatTranzacie)) = YEAR(DATE()) - 1) ;
2
S se tearg tranzaciile n care acelai broker reprezint att clientul vnztor, ct i pe cel
cumprtor.
DELETE * FROM Broker
WHERE CodBroker IN (
SELECT C1.CodBroker
FROM Client AS C1 INNER JOIN
(Tranzacie INNER JOIN Client AS C2
ON Tranzacie.CodClientVnztor = C2.CodClient)
ON C1.CodClient = Tranzacie.CodClientCumprtor
WHERE C1.CodBroker = C2.CodBroker) ;

Baze de date

55

Observaie: Tabelul Tranzacie trebuie compus de dou ori cu tabelul Client, pentru a obine att
informaii privitoare la cumprtorii, ct i la vnztorii aciunilor, care sunt evideniai n acelai
tabel. Dup cum s-a artat n subcapitolul 3.2, ntr-o astfel de situaie, vom referi tabelul Client
prin dou alias-uri distincte (C1 i C2), ca s putem indica sursa datelor (clientul vnztor, sau cel
cumprtor).

3.4.4 Modificarea datelor din tabele


Cererile SQL de modificare a datelor permit, ca la nivelul unei tabele specificate,
s fie actualizate tuplurile ce se conformeaz unui set de criterii, sau n absena
acestora, toate nregistrrile. Sintaxa generic a cererilor de acest tip este
urmtoarea:
UPDATE nume_tabel
SET nume_cmp_modificabil = {valoare|expresie|nume_cmp}[, ... n]
[FROM nume_tabel, list_tabele_asociate]
[WHERE criterii_actualizare] ;

Clauza SET specific atributele ale cror valori vor fi modificate, precum i noile
valori ale acestora, indicate n mod explicit, sau ca realizri ale unui anumit cmp,
sau expresie.
Atunci cnd nregistrrile care fac obiectul actualizrii trebuie corelate cu cele din
alte surse, se recurge la clauza FROM, realiznd compunerea tabelului vizat de
cererea de modificare a datelor, cu alte tabelele, asociate acestuia.
Exemple bazate pe tabelul generic A, definit n subcapitolul 3.2:
A ( a1, a2, a3, a4, a5, a6 )
Fraz SQL
UPDATE A
SET a4 = (a4 * 3)
WHERE a4 < (SELECT AVG (a4) FROM A) ;

Interpretare
Se actualizeaz nregistrrile tabelei A, prin
triplarea valorii cmpului a4, cnd aceasta
este mai mic dect media.

UPDATE A
SET a5 = (a5 * 2), a6 = 20
WHERE a5 < a6 ;

Se actualizeaz nregistrrile tabelei A


(cmpul a6 preia valoarea 20, iar a5 i
dubleaz valoarea), n condiiile n care a5 <
a6.

UPDATE A
SET a6 = (a6 * 1.75)
FROM A INNER JOIN B ON A.a1=B.a1
WHERE a5 IN (50, 200, 300) ;

n cazul nregistrrilor tabelei A care au


corespondent n B i pentru care realizrile
cmpului a5 sunt 50, 200 sau 300, valoarea
atributului a6 crete cu 75%.

Cereri SQL de modificare a datelor, care vizeaz tabelele bazei de date


TranzaciiBursiere, prezentat n subcapitolul 3.1:
Cerin
S se majoreze cu 30%
cotaiile de la data

Fraz SQL
UPDATE Cotaie
SET Valoare = (Valoare * 1.3)

56

Limbajul SQL

curent, pentru
aciunile emise de
societile din Iai.

FROM Cotaie INNER JOIN Societate


ON Cotaie.CodSocietate = Societate.CodSocietate
WHERE DatCotaie = DATE() AND LocalitateSocietate = Iai ;
Echivalent cu:
UPDATE Cotaie
SET Valoare = (Valoare * 1.3)
WHERE CodSocietate IN (SELECT CodSocietate FROM Societate
WHERE LocalitateSocietate = Iai)
AND DatCotaie = DATE() ;

Pentru o societate
specificat ca
parametru, cursul de la
data curent va fi
stabilit ca medie a
cotaiilor nregistrate
de aciunile societii
respective, la nivelul
anului curent.

PARAMETERS ReperSocietate Text(20) ;


UPDATE Cotaie
SET Valoare = (SELECT AVG (Valoare)
FROM Cotaie
WHERE CodSocietate = ReperSocietate
AND YEAR(DatCotaie) = YEAR(DATE()))
WHERE CodSocietate = ReperSocietate
AND DatCotaie = DATE() ;
Observaie: Subinterogarea returneaz cursul mediu, la nivelul anului
curent, al titlurilor emise de societatea indicat prin intermediul
parametrului ReperSocietate.

3.5 Controlul accesului


O baz de date poate fi considerat sigur doar dac operaiile executate asupra ei
constituie apanajul exclusiv al utilizatorilor autorizai. Aportul SQL la asigurarea
securitii unei baze de date se realizeaz prin intermediul unor instruciuni care
vizeaz gestionarea utilizatorilor i a drepturilor acestora de a crea sau accesa
obiecte ale bazei de date. Pentru ca astfel de instruciuni s poat fi executate n
contextul SGBD-ului MS Access, trebuie s se opteze pentru standardul de sintax
ANSI SQL-92 (Access Options Object Designers Query design: SQL Server
Compatible Syntax (ANSI92) - n cazul versiunii Access 2007).
Instruciunile care vizeaz controlul accesului la o baz de date faciliteaz
urmtoarele operaii:

Crearea utilizatorilor, respectiv a grupurilor de utilizatori:

CREATE USER nume_user1 parola_user1


[, nume_user2 parola_user2, ...]
CREATE GROUP nume_grup1 parola_grup1
[, nume_grup2 parola_grup2, ...]

Adugarea utilizatorilor la un grup

ADD USER nume_user1 [, nume_user2, ...] TO nume_grup

Acordarea drepturilor sau privilegiilor asupra tabelelor unei baze de date:

Baze de date

57

GRANT ALL PRIVILEGES | list_privilegii ON nume_tabel


TO PUBLIC | list_utilizatori | list_grupuri

unde, list_privilegii = {SELECT, UPDATE, DELETE, INSERT}


Instruciunea admite i dou argumente generice:
- ALL PRIVILEGES desemneaz ansamblul tuturor drepturilor asupra
tabelei vizate;
- PUBLIC refer toi utilizatorii, actuali, sau viitori, ai bazei de date.
Anularea drepturilor asupra tabelelor bazei de date:
REVOKE ALL PRIVILEGES | list_privilegii
ON nume_tabel FROM PUBLIC | list_utilizatori | lista_grupuri

tergerea utilizatorilor, respectiv a grupurilor:

DROP USER nume_user1 [, nume_user2

...]

DROP GROUP nume_grup1 [, nume_grup2, ...]

Observaie: Eliminarea unui grup din baza de date nu determin n mod implicit
i tergerea utilizatorilor ce fac parte din grupul respectiv.
Exemple de instruciuni de control al accesului, definite pe baza de date
TranzaciiBursiere, prezentat n subcapitolul 3.1:
1
S se creeze dou grupuri, pentru gestiunea drepturilor aferente clienilor ce particip la
tranzacii, respectiv a celor aferente brokerilor. Utilizatorilor din ambele grupuri li se va acorda
dreptul de consultare a tabelei Cotaii, care este accesibil tuturor userilor din baza de date. n
plus, brokerii primesc toate drepturile asupra tabelei ce stocheaz informaiile despre clieni.
CREATE GROUP Brokeri, Clienti ;
GRANT SELECT ON Cotaii
TO PUBLIC ;
GRANT ALL PRIVILEGES ON Client
TO Brokeri ;
2
Sunt definii doi useri de tip broker (brokerA, brokerB).
CREATE USER brokerA, brokerB ;
ADD USER brokerA, brokerB
TO Brokeri ;
Observaie: Ambii utilizatori motenesc drepturile i limitrile definite la nivelul grupului Brokeri.
3
Sunt restricionate drepturile utilizatorului brokerA, prin interzicerea efecturii de actualizri,
respectiv tergeri de nregistrri din tabelul Client. Ulterior, utilizatorul este eliminat din baza de
date.
REVOKE UPDATE, DELETE
ON Client FROM brokerA ;

58

Limbajul SQL

DROP USER brokerA;

4.5. Realizarea operatorilor relaionali n SQL


Operaiile algebrei relaionale prezentate n cadrul subcapitolului 1.2.2.2. pot s
fie uor realizate n SQL, pentru marea majoritate a operatorilor existnd clauze
SQL specifice.
Operatorul relaional de proiecie este reprezentat in SQL prin intermediul clauzei
SELECT, n cadrul creia se vor preciza cmpurile dup care se face proiecia.
Pentru a afia doar codul i localitatea de unde provin societile, clauza SQL este
urmtoarea:
SELECT CodSocietate, LocalitateSocietate
FROM Societate

Figura 3 Reprezentarea operatorului relaional de proiecie

Operatorul relaional de selecie este reprezentat n SQL cu ajutorul clauzei


WHERE, astfel pentru a afia societile din Braov, sintaxa SQL este
urmtoarea:
SELECT *
FROM Societate
WHERE LocalitateSocietate="Bucuresti"

Baze de date

59

Figura 4 Reprezentarea operatorului relaional de selecie

Reuniunea a dou tabele se realizeaz cu ajutorul clauzei UNION. Astfel


urmtorul exemplu prezint realizarea unei agende telefonice ce conine toate
numerele de telefon ale clienilor i societilor
SELECT Denumire, TelefonSocietate as Telefon,"Societate" as Tip
FROM Societate
UNION
SELECT NumeClient,Telefon, "Client" as Tip
FROM Client;

Figura 5 Realizarea reuniunii a dou tabele

Pentru reprezentarea diferenei a dou relaii (tabele) nu exist o clauz SQL


specific. Pentru a putea realiza diferena a dou tabele acestea trebuie s fie
compatibile, adic s aib acelai numr de cmpuri i de acelai tip. Se folosete
o selecie n care condiia va conine NOT IN mpreun cu subinterogarea ce
conine proiecia tabelei dup cmpurile comune cu prima tabel. n exemplul

60

Limbajul SQL

urmtor dorim vizualizarea brokerilor care nu au clieni, adic a brokerilor pentru


care codul nu se regsete printre valorile atributului CodBroker din tabelul
Client.
SELECT Broker.CodBroker
FROM Broker
WHERE CodBroker NOT IN (SELECT CodBroker FROM Client)

Figura 6 Reprezentarea diferenei a dou relaii

Produsul cartezian este operaia relaionala cel mai uor de realizat n SQL
deoarece nu necesit folosirea unui anume operator. Simpla enumerare a tabelelor
n cadrul clauzei FROM, fr specificarea anumitor condiii, genereaz ca rezultat
produsul cartezian al acelor tabele (Figura 7). Condiiile care se pot aduga fie n
cadrul clauzei FROM fie n cadrul clauzei WHERE determin selecia unui set
particular de valori, constituind, de fapt, reprezentarea n SQL a compunerii
tabelelor (Figura 10).
Pentru a realiza o list ce conine toate combinaiile posibile dintre valorile din
tabelul brokerilor i a societilor care sunt tranzacionate se folosete urmtoarea
sintax SQL:
SELECT *
FROM Broker, Societate

Baze de date

61

Figura 7 Realizarea produsului cartezian

Reprezentarea interseciei n cadrul SQL se realizeaz in cadrul clauzei WHERE


cu ajutorul operatorul IN i a subinterogrilor. Tabelele care particip la intersecie
trebuie sa fie compatibile, adic s aib acelai numr de atribute si de acelai tip.
n general tabelele utilizate n cadrul unei baze de date au structuri diferite i
pentru a ajunge la structuri de tabele compatibile se va folosi proiecia. Pentru a
identifica codurile de societi i datele la care au fost tranzacionate precum i
cotate se va folosi urmtoarea sintax SQL:
SELECT DISTINCT DataTranzactie, CodSocietate
FROM Tranzactie
WHERE DataTranzactie IN
(SELECT DataCotatie FROM Cotatie) AND CodSocietate IN
(SELECT CodSocietate FROM Cotatie)

Figura 8 Realizarea interseciei

62

Limbajul SQL

Compunerea este reprezentat n SQL prin intermediul condiiilor de compunere


din clauza WHERE. Pentru a clasifica societile n funcie de capitatul social,
categoriile fiind definite n cadrul tabelei Categorie, codul SQL este urmtorul :
SELECT CodSocietate, [ValoareNominala]*[NrActiuniEmise] AS
Capital, CategorieSocietate
FROM Societate, Categorie
WHERE [ValoareNominala]*[NrActiuniEmise]>=[CapitalMinim]
And [ValoareNominala]*[NrActiuniEmise]<=[CapitalMaxim]

Figura 9 Reprezentarea compunerii

Compunerea natural se realizeaz prin intermediul operatorului INNER JOIN


care va fi plasat alturi de condiiile de compunere n cadrul clauzei FROM.
Pentru a vizualiza societile i cotaiile aferente acestora, clauza SQL este
urmtoarea:
SELECT *
FROM LocalitateJudet
INNER JOIN Societate ON LocalitateJudet.Localitate =
Societate.LocalitateSocietate

Baze de date

63

Figura 10 Reprezentara compunerii naturale

Compunerea extern este reprezentat prin intermediul operatorilor LEFT JOIN


i INNER JOIN. Vizualizarea tuturor brokerilor i a clienilor lor se realizeaz
astfel:
SELECT Broker.CodBroker, Broker.NumeBroker, Client.CodClient,
Client.NumeClient
FROM Broker
LEFT JOIN Client ON Broker.CodBroker = Client.CodBroker;

Se observ n rezultat (Figura 11) c sunt afiate toate nregistrrile din tabela
Broker crora li se asociaz clienii consiliai, iar pentru brokerii al cror cod nu
i are corespondent n tabela Client se asociaz valoarea NULL.

Figura 11 Reprezentarea compunerii externe

Diviziunea este operatorul relaional a crei realizare n SQL este destul de


dificil. Pentru a identifica clienii care au cumprat aciuni la ambele societi

64

Limbajul SQL

avnd codul CABU i ADME va trebui s realizm diviziunea tabelului


Tranzacie la tabelul ce conine ca nregistrri cele dou coduri de societi
(Figura 12). Varianta de realizare prezentat presupune n prima etap
compunerea natural tabelelor Tranzacie i a tabelului ce conine ca nregistrri
cele dou coduri de societi (PROIECT CodSocietate (Societate)), urmeaz apoi s
obinem printr-o proiecie doar valorile cmpului CodClientCumparator i s
reinem, cu ajutorul seleciei, doar acele nregistrri pentru care numrul de
duplicate plus unu este egal cu numrul de nregistrri din tabelul mpritor.
Aceast modalitate de realizare a diviziunii relaionale este prezentat n figura
nr. 12.

Figura 12 Reprezentarea modalitii de realizare a diviziunii relaionale

Codul SQL pentru realizarea diviziunii relaionale este urmtorul:


SELECT CodClientCumparator
FROM Tranzactie, Societate
WHERE Tranzactie.CodSocietate=Societate.CodSocietate
GROUP BY CodClientCumparator
HAVING Count(Tranzactie.CodSocietate)=(SELECT COUNT(CodSocietate)
FROM Societate);

Figura 13 Reprezentarea diviziunii relaionale

Baze de date

65

3.7 Optimizarea interogrilor


Optimizarea interogrilor are drept scop creterea performanei acestora, apreciat
n general n funcie de timpul de rspuns la cererile de consultare i actualizare a
bazei de date.
n prezent, majoritatea S.G.B.D.-urilor dispun de instrumente specializate care
permit att monitorizarea, ct i optimizarea performanei interogrilor. Plecnd
de la o fraz SQL, pe baza unor algoritmi specifici, componente de tip optimizator
(optimizer) determin planul de execuie care permite rezolvarea cererii
respective, n condiiile maximizrii performanelor. Altfel spus, optimizatorul
gsete cea mai bun cale de soluionare a unei probleme date (cererea SQL
propriu-zis), ntr-un anumit context (baza de date, cu structura ei i nregistrrile
pe care le stocheaz). Devine deci evident c optimizarea interogrilor poate
ncepe prin implementarea anumitor reguli de definire a structurii datelor i de
specificare a cererilor SQL, ce pot avea consecine favorabile asupra
performanei.
3.7.1 Definirea structurii datelor
Dup cum a fost prezent ntr-un capitol anterior, normalizarea este un demers
justificat de raiuni ce in de asigurarea integritii datelor, dar care, adugm
acum, permite i mbuntirea performanei interogrilor. ntr-o baz de date
normalizat sunt eliminate datele redundante, astfel c paginile de date i cele
aferente indecilor sunt mai puine, iar cutrile se desfoar mai rapid.
Pe de alt parte, n cazul interogrilor ce reprezint sursa de date a unor aplicaii i
care au o durat de execuie nesatisfctoare, rezultatele pot fi stocate n tabele
temporare, de unde pot fi extrase mult mai rapid; de asemenea, salvarea
rezultatelor generate de subinterogrile lente poate reprezenta o alternativ mult
mai avantajoas la cererile imbricate. Pe de alt parte, datorit problemelor legate
de actualizarea coninutului acestor tabele temporare, astfel de soluii, care ncalc
practic principiul non-redundanei datelor, trebuie aplicate cu pruden, la nivelul
unor zone restrnse din baza de date i doar dac determin un ctig nsemnat n
planul performanei. n general, este util memorarea rezultatelor generate de
interogri ce trebuie executate frecvent i care se bazeaz pe tabele cu un volum
de nregistrri nsemnat, dar totodat, (relativ) stabil.
Un alt aspect legat de structura datelor, cu influene considerabile asupra
performanei interogrilor, vizeaz indecii creai la nivel de tabel. n raport cu
natura frazelor SQL ce folosesc ca surse de date tabelele n care au fost definii,
indecii acioneaz diferit, favoriznd accesul rapid la date, prin cereri de tip
SELECT i determinnd execuia mai lent a cererilor de tip INSERT, UPDATE,
sau DELETE, care implic nu doar modificri n cadrul paginilor de date, dar i

66

Limbajul SQL

actualizri ale indecilor. Aceste efecte contrarii conduc la concluzia c indecii


trebuie creai doar dac i unde este cazul aspecte care devin evidente doar prin
examinarea interogrilor definite la nivelul unei baze de date. Iat cteva sugestii
n acest sens:
Se recomand definirea de indeci pe cmpurile care apar n clauze WHERE.
Se consider urmtoarea cerere:
SELECT * FROM Client WHERE LocalitateClient = Iai ;

Dac tabela Client conine un index definit la nivelul cmpului


LocalitateClient, acesta va furniza repere de cutare rapid, accelernd
regsirea tuplurilor care se conformeaz restriciei; n caz contrar, este
necesar scanarea, sau parcurgerea secvenial a tuturor nregistrrilor din
tabel i evaluarea condiiei specificate n cauza WHERE pentru fiecare n
parte.
Definirea de indeci pe cmpurile utilizate la specificarea restriciilor nu aduce
un beneficiu real dect n condiiile n care atributele respective sunt utilizate
n mod nemijlocit ca operanzi ai unor operatori precum =, <, >, > =, < =,
LIKE, BETWEEN, IN, i nu n cadrul unor expresii. Spre exemplu, cererea
urmtoare nu poate valorifica un eventual index definit pe cmpul
DatAngajare, ntruct coloana respectiv este implicat ntr-o expresie ce
trebuie evaluat pentru fiecare nregistrare n parte (restricia vizeaz nu data,
ci anul angajrii, care trebuie determinat):
SELECT NumeBroker, PrenumeBroker
FROM Broker
WHERE YEAR(DatAngajare) > 2005 ;
Cmpurile cu valori foarte specifice (precum CNP, n cazul persoanelor fizice
i CUI, pentru persoanele juridice) pot fi utilizate cu succes la definirea de
indeci. Tocmai pentru c numrul apariiilor unei valori este redus (eventual
1), parcurgerea secvenial a mii, sau sute de mii de nregistrri, n cutarea
unor astfel de date este neeficient, impunnd crearea de indeci. Pe de alt
parte, indexarea unui cmp ce admite valori generice se dovedete a fi, de cele
mai multe ori, inutil. Spre exemplu, n cazul indecilor definii pe atribute de
tipul CategorieClient (PF/PJ), Sex (F/M), TipTranzacie (Vnzare/Cumprare)
etc., regsirea datelor este ngreunat de numrul mare de nregistrri pentru
care cmpul-index are valori identice, fiind uneori chiar mai lent dect n
cazul cutrii secveniale, neindexate (aceasta deoarece parcurgerea indecilor
trebuie urmat de accesarea paginilor n care se afl datele propriu-zise).
n cererile SQL ce folosesc date din mai multe surse, compunerile de tabele
pot fi accelerate prin intermediul indecilor definii pe cmpurile de legtur.
n mod uzual, astfel de compuneri au la baz relaii de tipul cheie primar cheie extern; cum valorile cheii primare sunt n mod implicit indexate,

Baze de date

67

deducem c poate fi util definirea unui index n tabelul corespondent, la


nivelul cheii externe. n plus, prin crearea unor astfel de indeci n cadrul
tabelelor dependente se accelereaz verificarea restriciilor de integritate
referenial, cu ocazia modificrilor operate n tabelul referit, sau n cel
dependent, prin cereri de tip INSERT, UPDATE, sau DELETE.
De asemenea, atributele care n cererile SQL sunt specificate drept criterii de
grupare (GROUP BY), sau de sortare (ORDER BY) a datelor, atributele
folosite ca argumente ale funciilor MAX i MIN, precum i cele vizate de
restricii (WHERE / HAVING) privind ncadrarea ntr-un interval de valori,
constituie, de asemenea, buni candidai pentru definirea de indeci.

3.7.2 Definirea cererilor SQL


Pe lng influena exercitat de structura datelor, maniera n care sunt specificate
cererile SQL condiioneaz, n mod decisiv, mecanismul de execuie i timpul de
rspuns al interogrilor definite asupra unei baze de date; n cele ce urmeaz,
furnizm cteva recomandri:
Ca regul, este bine s se evite afiarea unor atribute i/sau valori calculate ce
nu prezint interes. Efectuarea unor prelucrri precum concatenrile de texte,
schimbarea formatului datelor etc., din orice alte raiuni cu excepia celor strict
obiective, precum i recurgerea la formula SELECT * din comoditate, pot
avea consecine nefaste n planul performanei. Spre exemplu, considerm
urmtoarele cereri:
SELECT NumeClient FROM Client
WHERE NumeClient LIKE M* ;
i
SELECT * FROM Client
WHERE NumeClient LIKE M* ;
Cele dou interogri sugereaz oportunitatea crerii unui index n tabelul
Client, pe atributul NumeClient. Dei un astfel de index accelereaz execuia
ambelor cereri, prima dintre acestea va nregistra un timp mai bun. Aceast
diferen n planul performanei se datoreaz manierei diferite n care au fost
specificate instruciunile de selecie a datelor: SELECT NumeClient, fa de
SELECT *. Dei poate prea minor, ntruct vizeaz doar cmpurile
afiabile, o astfel de diferen are o cauz mai puin vizibil, dar cu consecine
extrem de importante asupra performanei interogrilor: mecanismul de
regsire a datelor n tabelele indexate i relaiile dintre paginile de date i cele
aferente indecilor. n ambele cereri, iniial sunt explorate paginile de indeci,
pentru identificarea numelor care ncep cu litera M, ns din acest punct,
execuia cererilor urmeaz un parcurs diferit:

68

Limbajul SQL
n primul caz, numele sunt returnate direct, fr a mai fi nevoie de
accesarea paginilor de date popriu-zise, ntruct valorile ce trebuie afiate
(NumeClient) sunt integral acoperite de index.
Execuia celei de-a doua cereri trebuie s continue cu identificarea
paginilor de date care conin nregistrrile corespunztoare valorilor
NumeClient regsite prin intermediul indexului, ntruct trebuie afiate i
realizrile celorlalte cmpuri (neindexate).
Concluzia care trebuie s se desprind din acest exemplu este c numrul
cmpurilor afiabile trebuie limitat la minimul necesar i nu c ar trebui
definii indeci pe toate cmpurile ce ar putea, la un moment dat, s fie
selectate spre afiare, ntruct beneficiile de performan pot fi contrabalansate
de costurile impuse de actualizarea i folosirea acestor indeci. n plus, n
cazul unui index care include mai multe cmpuri, este posibil ca parcurgerea
secvenial a nregistrrilor tabelului pe care indexul a fost definit s necesite
un consum de timp mai redus dect utilizarea indexului.
n cadrul unei cereri SQL, ori de cte ori este posibil, se vor prefera
compunerile de tabele n defavoarea subinterogrilor, ntruct acestea din
urm impun parcurgerea secvenial a nregistrrilor tabelului din interior
pentru fiecare rnd al tabelului exterior. Spre exemplu, cererea:
SELECT * FROM Societate
WHERE CodSocietate IN
(SELECT CodSocietate FROM Tranzacie) ;
poate fi rescris astfel:
SELECT DISTINCT Societate.*
FROM Societate INNER JOIN Tranzacie ON
Societate.CodSocietate = Tranzacie.CodSocietate ;
Observaie: Dei specificatorul DISTINCT este necesar dac dorim ca cele
dou cereri s produc rezultate similare, dup cum vom arta n cele ce
urmeaz, acesta poate afecta n mod negativ performana interogrilor.
Avnd n vedere consumul de timp necesar ca liniile din fiecare tabel s poat
fi combinate cu tuplurile din toate celelalte tabele-surs, se impune ca
interogrile ce recurg la operaii tip produs cartezian s fie bine justificate, n
caz contrar ele putnd deveni cu uurin contra-productive, mai cu seam
dac au la baz tabele de cu un volum mare de nregistrri. Atunci cnd prin
clauzele WHERE sau GROUP BY, sau prin specificatorul DISTINCT, se
urmrete limitarea setului de nregistrri returnat de o astfel de operaie, cel
mai probabil, aceasta nici nu era absolut necesar, fiind mai indicat o
jonciune intern (INNER JOIN), care reprezint totodat o opiune mult mai
avantajoas n planul performanei.

Baze de date

69

Compunerile de tip OUTER JOIN se recomand a fi utilizate cu pruden,


ntruct ele determin preluarea integral i implicit, parcurgerea secvenial a
nregistrrilor tabelei principale.
De asemenea, dac este posibil, se va renuna la eliminarea duplicatelor prin
DISTINCT, sau prin UNION (UNION ALL poate fi utilizat ca alternativ la
UNION), ntruct o astfel de operaie impune sortarea prealabil a
nregistrrilor, o prelucrare suplimentar, care afecteaz n mod negativ
performana.
Cu excepia cazului n care este absolut necesar, specificarea unor cmpuri,
ce nu au fost desemnate drept indeci, n clauza ORDER BY, trebuie evitat.
Calculele complicate i expresiile elaborate, care recurg la diverse funcii,
trebuie limitate la minimul necesar. O decizie n acest sens trebuie s plece de
la analiza modului n care este executat expresia respectiv; spre exemplu,
funcia IIF prezint dezavantajul c nainte de a returna rezultatul, necesit att
evaluarea expresiei aferente ramurii TRUE, ct i pe cea asociat ramurii
FALSE.
n plus, este bine s se evite plasarea cmpurilor calculate la nivelul
subinterogrilor, poziia cea mai indicat pentru acestea fiind, n msura n
care acest lucru este posibil, interogarea principal.
Dac operatorul IN este nsoit de o list de valori constante i nu returnate de
o subinterogare - IN (SELECT...) -, elementele listei vor fi enumerate, pe ct
este posibil, n ordinea frecvenei de apariie, prin raportarea la operandul care
l precede pe IN. Spre exemplu ntr-o restricie de genul:
LocalitateClient IN (Bucureti, Iai, Sibiu, ...)
se acord prioritate valorilor cel mai probabil a se regsi printre realizrile
cmpului LocalitateClient, deoarece operatorul IN returneaz TRUE imediat
ce a fost ntlnit prima coresponden (aici, primul element care coincide cu
valoarea cmpului LocalitateClient). Drept urmare, parcurgerea restului listei
nu mai este necesar, iar viteza de execuie a interogrii crete.

Bibliografie
1. Allison C., Berkowitz N., SQL for Microsoft Access (2nd Edition),
Wordware Publishing, 2008
2. Bagui S., Earp, R., Learning SQL: A Step-by-Step Guide Using Access,
Addison Wesley, 2003
3. Florescu V., Nstase P., Berbec F., Baze de date Fundamente teoretice i
practice, Infomega, 2002
4. Forta B., SQL n lecii de 10 minute, Teora, 2004

70

Limbajul SQL
5. Henderson K., Transact SQL, Teora, 2002
6. Kriegel A., Trukhnov, B.M., SQL Bible, Wiley Publishing, 2003
7. Nstase P., Mihai F., Coscescu L., Brbulescu B., Stanciu A., ova R.,
Covrig L., Baze de date Microsoft Access 2000, Teora, 2000
8. *** http://office.microsoft.com/ro-ro/access

S-ar putea să vă placă și