Sunteți pe pagina 1din 46

Unitatea de învăţare 4

Interogarea datelor

Cuprins
Obiectivele unităţii de învăţare 4 .................................................................................................. 68
4.1. Funcţii predefinite SQL Server .............................................................................................. 68
4.2. Obiecte de tip View ............................................................................................................... 84
4.3. Proceduri stocate .................................................................................................................... 89
4.3.1. Proceduri de sistem ............................................................................................................. 90
4.3.2. Declararea variabilelor........................................................................................................ 90
4.3.3. Parametrizarea procedurilor stocate ................................................................................... 91
4.3.4. Structuri de control al fluxului............................................................................................ 93
4.4. Funcţii definite de utilizator................................................................................................... 96
4.5. Utilizarea cursoarelor........................................................................................................... 104
4.6. Exerciţii propuse şi rezolvate............................................................................................... 108
Bibliografie Unitatea de învăţare 4 ............................................................................................. 112
68 Baze de date – Introducere în SQL Server

Obiectivele unităţii de învăţare 4


 Însuşirea cunoştinţelor necesare pentru a crea obiectele de tip view, de a utiliza funcţiile
predefinite sau definite de utilizator, de a crea proceduri stocate.

4.1. Funcţii predefinite SQL Server


Limbajul Transact SQL pune la dispoziţia programatorilor un set complet de funcţii ce facilitează realizarea
de calcule complexe sau conversii de date. În continuare este prezentată o selecţie a celor mai utile
funcţii grupate pe categorii:

Funcţii pentru conversia între tipuri de date


 Funcţia CONVERT

Converteşte rezultatul unei expresii într-un anumit timp de date. Sintaxa:

CONVERT (tip_date_rezultat [(lungime)], expresie [,


stil_conversie])

• tip_date_rezultat – tipul de date în care se converteşte expresie


• lungime – lungimea tipului de date, doar pentru tipurile de date care suportă
• expresie – orice expresie admisibila SQL, al cărei rezultat se va converti în tip_date_rezultat
• stil_conversie – cod folosit atunci când se doreşte utilizarea unor modele de conversie SQL;
Câteva coduri uzuale pentru stil_conversie pentru conversia in/din data/ora:

Cod Format data/ora rezultat


101 mm/dd/yyyy
103 dd/mm/yyyy
108 hh:mi:sec
113 dd mon yyyy hh:mi:ss:mmm

Exemplul 1

SELECT getdate()

Se returnează data serverului în formatul implicit. Aşa cum se observă din imaginea anterioară,
formatul implicit al datei (componenta calendaristică) este yyyy-mm-dd. Atunci când se doreşte
introducerea unei date calendaristice într-o bază de date sau obţinerea unei date calendaristice din
baza de date, în mod implicit, se va utiliza formatul datei serverului. În cazul în care acest format nu
Unitatea de învăţare 4
Interogarea datelor
este pe placul utilizatorului, se poate schimba formatul de introducere/afişare cu ajutorul funcţiei
CONVERT. De asemenea trebuie să amintim că dacă nu se utilizează funcţia CONVERT şi utilizatorul
care introduce date calendaristice nu cunoaste formatul serverului, se pot memora date eronate sau
se pot obţine erori. Utilizând funcţia CONVERT se poate obţine data calendaristică şi în formatul
dd/mm/yyyy, utilizând codul 103 pentru parametrul stil_conversie.

SELECT CONVERT(char(10), getdate(), 103)

Utilizând codul 113 pentru parametrul stil_conversie, se obţine:

SELECT CONVERT(char(30), getdate(), 113)

Exemplul 2

În acest exemplu vom prezenta modul cum se specifică corect o dată calendaristică introdusă de
utilizator în formatul propriu (dd/mm/yyyy), dar transformată cu ajutorul funcţiei CONVERT:

SELECT CONVERT(date, '10/12/2008', 103)

Dacă nu s-ar fi utilizat parametrul stil_conversie, varianta implicită de introducere a datei


calendaristice ar fi fost eronată (în cazul în care formatul implicit nu este cunoscut sau este ignorat de
utilizator):

SELECT CONVERT(date, '10/12/2008')

În acest caz se observă că data calendaristică 10.decembrie.2008 a fost interpretată ca fiind


12.octombrie.2008.
Pentru a preîntâmpina erorile care pot fi generate de manipularea greşită a datelor calendaristice,
recomandăm folosirea funcţiei CONVERT (cu parametrul stil_conversie) în toate situaţiile în care se
utilizează date calendaristice în alt format decât cel al serverului.

Exemplul 3

Utilizarea funcţiei CONVERT pentru transformarea datelor de natura numerică:


SELECT TOP 5 NrContract, TarifNegociat,
CONVERT(decimal(20,1), TarifNegociat) As TarifOZecimala,
CONVERT(numeric(20,2), TarifNegociat) As Tarif2Zecimal2 FROM
Contract FROM Contract
70 Baze de date – Introducere în SQL Server

Exemplul 4

Utilizarea componentei timp, din data calendaristică:

SELECT CONVERT(time, getdate())

 Funcţia CAST

Are acelaşi rolul ca şi funcţia convert (converteşte rezultatul unei expresii întrun anumit timp de
date) . Sintaxa este mai simplă şi nu prezintă toate facilităţile funcţiei convert:
CAST(Expresie AS Tip de data)

Funcţii pentru date de tip calendaristic


 Funcţia GETDATE()

Returnează data şi ora serverului.

 Funcţia DAY
Returnează ziua dintr-o dată calendaristică. Sintaxa:
DAY (expresie)

 Funcţia MONTH

Returnează luna dintr-o dată calendaristică. Sintaxa:

MONTH(expresie)

 Funcţia YEAR

Returnează anul dintr-o dată calendaristică. Sintaxa:


YEAR(expresie)
Unitatea de învăţare 4
Interogarea datelor
Exemplu
SELECT top 5
day(DataContract) as Zi,
month(DataContract) as Luna,
year(DataContract) as An
FROM Contract

 Funcţia DATEPART

Extrage dintr-o data calendaristica/ora o anumită informatie calendaristica, identificata printr-un cod.
Sintaxa:
DATEPART (informaţie_calendaristica, expresie_data/ora) În tabelul
următor sunt prezentate câteva valori uzualepentru parametrul informatie_calendaristica:

Cod
Rezultat
informatie_calendaristica
year An
month Luna
day Zi
dayofyear Numar zi din
an
quarter Trimestru
week Numar saptamana din
an
hour Ora
minute Minutele
second Secundele

Exemplu
Extragerea din data curentă a serverului a mai multor informaţii calendaristice.

SELECT DATEPART(DAY, getdate()) as ZI,


DATEPART(MONTH, getdate()) as LUNA,
DATEPART(YEAR, getdate()) as AN,
DATEPART(DAYOFYEAR, getdate()) as NRZI,
DATEPART(QUARTER, getdate()) as TRIM,
DATEPART(WEEK, getdate()) as SAPT,
DATEPART(HOUR, getdate()) as ORA,
DATEPART(MINUTE, getdate()) as MINUT, DATEPART(SECOND,
getdate()) as SEC
72 Baze de date – Introducere în SQL Server

 Funcţia DATEDIFF

Sintaxa:
DATEDIFF(informaţie_calendaristica, data/ora start, data/ora final) Calculează
diferenţa dintre două date calendaristice (data/ora final şi data/ora start). Rezultatul este furnizat
într-un anumit tip de informaţie calendaristica, identificată printr-un cod (valorile uzuale sunt
prezentate la funcţia DATEPART. Exemplu
Calcularea diferenţei între data 1/1/2009 şi 15/6/2006 exprimată în mai multe tipuri de informaţie
calendaristică:

SELECT
DATEDIFF(DAY, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as ZILE,
DATEDIFF(MONTH, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as LUNI,
DATEDIFF(YEAR, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as ANI,
DATEDIFF(DAYOFYEAR, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as NRZILE,
DATEDIFF(QUARTER, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as TRIM,
DATEDIFF(WEEK, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as SAPT,
DATEDIFF(HOUR, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as ORE,
DATEDIFF(MINUTE, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as MINUT,
DATEDIFF(SECOND, CONVERT(datetime, '15/6/2006', 103),
CONVERT(datetime, '1/1/2009', 103)) as SECUNDE

 Funcţia DATEADD

Sintaxa:
DATEADD (informaţie_calendaristica, n, data/ora start)
Calculează o data calendaristică (viitoare sau anterioară), plecând de la o anumită dată calendaristică
(data/ora start) la care se adăuga un n (in format informaţie calendaristică aşa cum a fost prezentat
Unitatea de învăţare 4
Interogarea datelor
la funcţia DATEPART). În cazul în care se doreşte calcularea unei date anterioare faţă de data luată ca
bază (data/ora start), argumentul n se precizează cu minus. Exemplu
Calcularea datei de peste 1000 zile faţă de data de 1/1/2009 şi a datei de acum 10000 zile faţă de
1/1/2009.

SELECT
DATEADD(DAY, 10000, CONVERT(datetime, '1/1/2009', 103)) as
DataViitoare,
DATEADD(DAY, -10000, CONVERT(datetime, '1/1/2009', 103)) as
DataAnterioara

Funcţii pentru prelucrarea şirurilor de caractere


 Funcţia LTRIM

Sintaxa:
LTRIM(expresie)

Elimină spaţiile nesemnificative de la stânga unei expresii de tip şir de caractere.


 Funcţia RTRIM
Sintaxa:
RTRIM(expresie)
Elimină spaţiile nesemnificative de la dreapta unei expresii de tip şir de caractere Exemplu

SELECT LTRIM(' BAZE DE DATE') as SpatiiStanga,


RTRIM('BAZE DE DATE ') as SpatiiDreapta,
LTRIM(RTRIM(' BAZE DE DATE ')) as SpatiiStDr

 Funcţia LEN

Sintaxa:
LEN(expresie)

Returnează numărul de caractere dintr-o expresie.

 Funcţia LOWER
74 Baze de date – Introducere în SQL Server

Sintaxa:
LOWER(expresie)

Returnează şirul de caractere din expresie scris cu litere mici.

 Funcţia UPPER

Sintaxa:
UPPER(expresie)

Returnează şirul de caractere din expresie scris cu litere mari.

Exemplu

SELECT TOP 10 NumeAng, PrenumeAng,


LOWER(NumeAng) as NumeLitereMici,
UPPER(NumeAng) as NumeMajuscule,
LEN(PrenumeAng) as NrLiterePrenume FROM Angajat

 Funcţia LEFT
Sintaxa:
LEFT(expresie, n)

Returnează n caractere de la stânga unei expresii şir de caractere

 Funcţia RIGHT

Sintaxa:
RIGHT(expresie, n)

Returnează n caractere de la dreapta unei expresii şir de caractere

 Funcţia SUBSTRING
Unitatea de învăţare 4
Interogarea datelor
Sintaxa:
SUBSTRING (expresie, start, n)
Returnează n caractere dintr-o expresie şir de caractere, începând de la poziţia start.
Exemplu

SELECT TOP 10 NumeAng,


LEFT(LTRIM(NumeAng), 4) as PatruStanga,
RIGHT(RTRIM(NumeAng), 4) as PatruDreapta,
SUBSTRING(NumeAng, 3, 2) as DouaDupaTrei FROM Angajat

Alte funcţii matematice

 Funcţia POWER
Returnează valoarea unui număr ridicat la o putere.

Sintaxa
POWER(expresie numerică,puterea)

Exemplu:

SELECT POWER(2,3) as [ 2 LA PUTEREA 3]

 Funcţia ABS

Funcţia ABS returnează valoarea absolută a unei expresii numerice.


Sintaxa:
ABS (expresie numerica) Exemplu:

SELECT ABS (123) AS [Ex1], ABS(-23) AS [Ex2]


76 Baze de date – Introducere în SQL Server

 Funcţia SIGN

Sintaxa: SIGN(expresie numerică)

Returnează una dintre valorile:


• -1 dacă expresia este negativă
• 0 dacă expresia este zero
• +1 dacă expresia este pozitivă Exemplu:
SELECT SIGN(-10) AS EX1, SIGN(0) AS EX2 , SIGN(100) AS EX3

 Funcţiile CEILING, FLOOR şi ROUND

Sunt funcţii utilizate pentru rotunjirea valorilor numerice. Diferenţele dintre aceste funcţii sunt redate în
exemplul următor:

SELECT CEILING (23.1) AS EX1, CEILING(23.8) AS EX2,


FLOOR(23.1) AS EX3, FLOOR(23.8) AS EX4,
ROUND(23.1,0) AS EX5, ROUND(23.8,0) AS EX5

Funcţii de tip agregat


Prin intermediul acestor funcţii se pot realiza calcule la nivelul grupurilor de înregistrări. Sintaxele
funcţiilor ce permit calculul mediei, sumei, minimului, maximului sau a numărului de valori la nivelul
unui grup de înregistrări sunt următoarele:

AVG ( [ DISTINCT ] expresie )


SUM ( [DISTINCT ] expresie )
MIN (expresie)
MAX (expresie)
COUNT ([ DISTINCT ] expresie | * } )
Unitatea de învăţare 4
Interogarea datelor
Funcţiile de tip agregat pot fi utilizate in expresii într-o frază SQL în cadrul uneia dintre următoarele
instrucţiuni/clauze:
 SELECT
 HAVING
 COMPUTE

• Dacă o funcţie agregat este utilizată în cadrul instrucţiunii SELECT, celelalte câmpuri preluate din
sursa de date în instrucţiunea SELECT se vor regăsi drept câmpuri de grupare în cadrul instrucţiunii
GROUP BY.
• Clauza HAVING permite specificarea de condiţii la nivelul grupurilor de înregistrări .
• Instrucţiunea COMPUTE permite calcularea de totaluri generale sau subtotaluri şi este specificată la
sfârşitul instrucţiunii de selecţie (după ORDER BY).

Specificarea opţiunii DISTINCT în cazul funcţiilor AVG, SUM sau COUNT permite ca valorile identice
să fie considerate o singură dată în momentul efectuării calculelor.
Specificarea simbolului * între parantezele funcţiei COUNT va conduce la numărarea tuturor valorilor
domeniului pe care se aplică funcţia, inclusiv a valorilor nule.
Exemple:
Se dă tabelul Colaboratori:

1. Calculaţi câte coduri de departamente sunt in tabelul Colaboratori:


SELECT COUNT(CODDEPARTAMENT) As EX1,
COUNT(DISTINCT CodDepartament) AS Ex2,
COUNT(*) AS Ex3
FROM Colaboratori
78 Baze de date – Introducere în SQL Server

Rezultatele interogării sunt prezentate în figura


alăturată.

Observaţie: Clauza Group By nu este necesară întrucât funcţia Count se aplică întregului domeniu,
iar în instrucţia SELECT nu figurează şi alte câmpuri înafara funcţiilor.
Cele trei exemple de utilizare a funcţiei COUNT returnează rezultate diferite deoarece al doilea
exemplu utilizează opţiunea DISTINCT, iar al 3-lea va număra şi valoarea NULL prezentă la unul
dintre angajaţi în câmpul CodDepartament.
2. Calculaţi salariul minim si salariul maxim pe fiecare compartiment unde sunt mai mult de doi
Angajati.
SELECT CodDepartament, MIN(salariu) as SalariuMinim,
MAX(salariu) as SalariuMaxim
FROM Colaboratori
GROUP BY CodDepartament
HAVING COUNT(CNP) > 2

3. Să se obţină lista alfabetică a angajaţilor din departamentul IT şi să se calculeze total general


salarii.
Observaţie: Întrucât se doreşte utilizarea unei funcţii de grupare împreună cu o listă de selecţie ce
conţine înregistrări negrupate se va utiliza clauza COMPUTE

SELECT NUME, SALARIU


FROM Colaboratori
WHERE CodDepartament='IT'
ORDER BY NUME
COMPUTE SUM(SALARIU)

4. Să se obţină lista angajaţilor ordonată alfabetic pe departamente şi să se calculeze salariul mediu


pe fiecare departament:

SELECT NUME, SALARIU, CodDepartament


FROM Colaboratori
ORDER BY CodDepartament, NUME
Unitatea de învăţare 4
Interogarea datelor
COMPUTE AVG(SALARIU) BY CodDepartament

Observaţie: În acest caz, clauza COMPUTE permite specificarea câmpului pe baza cărora se vor realiza
subtotaluri utilizând sintaxa
COMPUTE <funcţie> BY nume_camp

Utilizarea clauzei COMPUTE BY necesită ca rezultatele selecţiei să fie ordonate după câmpul precizat
în instrucţiunea BY (în cazul de faţă CodDepartament). Rezultatele exemplului precedent sunt
prezentate în figura următoare:

Funcţii de clasificare
 ROW_NUMBER( ) OVER (< order_by_clause > )

Atribuie un număr de ordine fiecărei înregistrări in funcţie de un criteriu de ordonare specificat în clauza
OVER.
 RANK( ) OVER (< order_by_clause > )

Atribuie un rang fiecărei înregistrări în funcţie de un criteriu de ordonare.

Înregistrările cu aceleaşi valori pe câmpul după care se face ordonarea vor avea acelaşi rang.
 NTILE (N) OVER (order_by_clause > )

Permite distribuirea înregistrărilor dintr-un set de rezultate pe N intervale funcţie de un criteriu de


ordonare.
Exemple:
• Sa se numeroteze angajaţii în ordine descrescătoare a salariilor.
80 Baze de date – Introducere în SQL Server

• Utilizând funcţia RANK să se atribuie un rang angajaţilor după salariu. Să se împartă angajaţii
în trei grupe salariale, în ordine descrescătoare a salariilor.

SELECT Nume, Salariu,


ROW_NUMBER() OVER (ORDER BY SALARIU DESC) AS Ex1,
RANK() OVER (ORDER BY SALARIU DESC) AS Ex2,
NTILE(3) OVER (ORDER BY SALARIU DESC) AS Ex3
FROM Colaboratori
ORDER BY SALARIU DESC

Observaţie: Clauza ORDER BY din instrucţiunea SELECT poate să difere de cea din clauza OVER utilizată
în cadrul funcţiilor ROW_NUMBER, RANK sau NTILE.

Alte funcţii
 ISNULL ( expresie , valoare de inlocuit )
Funcţia ISNULL evaluează dacă o expresie conţine valoarea NULL şi, în cazul în care condiţia este
îndeplinită, înlocuieşte expresia cu valoarea specificată ca al doilea argument .
 ISDATE (expresie )
Funcţia ISDATE verifică dacă o expresie poate fi evaluată ca o dată calendaristică validă. În cazul în care
condiţia este îndeplinită returnează valoarea 1, în caz contrar 0.
 ISNUMERIC(expresie)
Funcţia ISNUMERIC evaluează dacă o expresie poate fi considerată valoare numerică. În cazul în care
condiţia este îndeplinită returnează valoarea 1, în caz contrar 0.
 Funcţia NEWID()
Returnează o valoare de tip UNIQUEIDENTIFIER
Se poate utiliza în orice frază SQL sau în cadrul proprietăţii Default Value or Binding, pentru atribute
de tipul unique identifier în scopul alocării de valori în mod automat.

Exemplul 1
Utilizarea din SQL:
Unitatea de învăţare 4
Interogarea datelor

SELECT NEWID ()

Exemplul 2
Utilizarea în cadrul proprietăţii Default Value or Binding, într-un tabel unde cheia primară CodModul,
este de tip uniqueidentifier:

Figura 1 Utilizarea funcţiei newid()

 Funcţia CASE

Sintaxa varianta 1:
CASE expresieA
WHEN expresieB1 THEN expresie_Rezultat
[WHEN expresieB2 THEN expresie_Rezultat]

[ELSE expresie_Rezultat_F]
END
82 Baze de date – Introducere în SQL Server

În această variantă funcţia evaluează expresieA şi în cazul în care rezultatul acesteia verifică rezultatul
evaluării pentru expresieB1 (sau expresieB2, etc.), se execută expresie_Rezultat. În cazul în care nu
se verifică niciuna din expresiile expresieB1, expresieB2, … se va executa expresie_Rezultat_F.

Sintaxa varianta 2:
CASE
WHEN expresie_logica1 THEN expresie_Rezultat
[WHEN expresie_logica2] THEN expresie_Rezultat

[ELSE expresie_Rezultat_F]
END

În această variantă se execută prima expresie_Rezultat luată în ordinea scrierii, unde expresie_logică
este evaluată cu valoarea “adevărat” (TRUE). În cazul în care niciuna din expresiile
logice nu este adevărată se execută expresie_Rezultat_F. Exemplul 1
Să se calculeze o primă contractuală pentru fiecare angajat care a lucrat la un contract. Prima se va calcula
astfel:
• Pentru angajaţii care au lucrat toată perioada unui contract, se acordă o primă de 10% din
tariful negociat al contractului;
• Pentru angajaţii care nu au lucrat toată perioada unui contract, se acordă o primă de 8% din
tariful negociat al contractului, proporţional cu numărul de zile lucrate la contract;

SELECT Angajat.CNPAngajat, NumeAng, PrenumeAng,


Contract.NrContract, TarifNegociat,
DateDIFF(DAY, DataInceput, DataSfarsit) as
NrZileLucrate,
DateDiff(DAY, DataContract, DataFinContract) As
NrZileContract,
CASE DateDIFF(DAY, DataInceput, DataSfarsit)
WHEN DateDiff(DAY, DataContract, DataFinContract) THEN
TarifNegociat * 0.1
ELSE
TarifNegociat * 0.08 * DateDIFF(DAY, DataInceput,
DataSfarsit)/DateDiff(DAY, DataContract,
DataFinContract)
END As Prima2008
FROM Angajat INNER JOIN Lucreaza ON
Angajat.CNPAngajat=Lucreaza.CNPAngajat
INNER JOIN Contract ON
Lucreaza.NrContract=Contract.NrContract
Unitatea de învăţare 4
Interogarea datelor

Exemplul 2

Să se calculeze o primă anuală acordată fiecărui angajat, ca procent din tariful negociat al fiecărui
contract la care a lucrat, în funcţie de numărul de zile pe care le-a lucrat. Procentul din tariful negociat
este:
• 5% pentru cei care au lucrat sub 50 zile la un contract;
• 7% pentru cei care au lucrat între 50 şi 100 zile la un contract;
• 9% pentru cei care au lucrat între 100 şi 150 zile la un contract;
• 11% pentru cei care au lucrat între 150 şi 300 zile la un contract;
• 12% pentru cei care au lucrat peste 300 zile la un contract;

SELECT Angajat.CNPAngajat, NumeAng, PrenumeAng,


Contract.NrContract, TarifNegociat,
DateDIFF(DAY, DataInceput, DataSfarsit) as NrZile,
CASE
WHEN DateDIFF(DAY, DataInceput, DataSfarsit) <50 THEN
TarifNegociat * 0.05
WHEN DateDIFF(DAY, DataInceput, DataSfarsit) <100 THEN
TarifNegociat * 0.07
WHEN DateDIFF(DAY, DataInceput, DataSfarsit) <150 THEN
TarifNegociat * 0.09
WHEN DateDIFF(DAY, DataInceput, DataSfarsit) <300 THEN
TarifNegociat * 0.1
ELSE
TarifNegociat * 0.12
END As Prima2008

FROM Angajat INNER JOIN Lucreaza ON


Angajat.CNPAngajat=Lucreaza.CNPAngajat
INNER JOIN Contract ON Lucreaza.NrContract=Contract.NrContract
84 Baze de date – Introducere în SQL Server

4.2. Obiecte de tip View


Un obiect de tip View reprezintă un tabel virtual al cărui conţinut se obţine în urma execuţiei unei
interogări. Datele obţinute cu un View nu sunt stocate separat în baza de date împreuna cu View-ul.
Nu sunt memorate nici măcar câmpurile obiectului View. Atât datele cât şi câmpurile (structura
tabelară) din View sunt obţinute în mod dinamic la fiecare execuţie a interogării care stă la bază. După
crearea unui obiect View, având în vedere că din punct de vedere funcţional este similar unui tabel
(virtual) din baza de date, obiectul View poate fi utilizat în mod asemănător acestora.
Categorii de obiecte View:  Standard – utilizează interogări uzuale de selecţie pe unul sau mai multe
tabele ale bazei de date;
 Indexate – utilizează un index pentru a creşte performanţele accesului la date prin intermediul
unui View. Performanţa este foarte ridicată, doar în cazul în care datele accesate nu suferă
modificări dese în timp;
 Partiţionate – se utilizează pentru a accesa seturi de date cu structură identică, distribuite pe unul
sau mai multe servere. Pot fi utilizate cu succes pentru implementarea bazelor de date federative.

Gestiunea obiectelor View, poate fi făcută:


 utilizând interfaţa grafică dedicată pusă la dispoziţie prin SQL Server Management Studio;
 direct dintr-o fraza SQL (de exemplu dintr-o frază SQL executată într-o fereastră Query);

Crearea unui View standard folosind interfaţa grafică dedicată din SQL Server
Management Studio
Pentru a exemplifica crearea unui obiect View, în acest mod, se parcurg următorii paşi (pentru exemplu
definim un obiect View pentru selectarea în ordine cronologică a tuturor contractelor din perioada
1/1/2008-2/2/2008 şi ofertelor pe baza cărora s-au încheiat):

a. Se acţionează clic dreapta pe secţiunea Views a bazei de


date şi apoi New View…:

b. Se aleg obiectele participante în View (tabele, view-uri,


funcţii, sinonime):
Unitatea de învăţare 4
Interogarea datelor

Figura 2

c. Se stabilesc câmpurile selectate în View, criteriile de selecţie (Filter), criteriile de grupare şi cele
de ordonare a datelor (Sort Type şi Sort Order):

Figura 3

Se observă că pe măsură ce se defineşte obiectul View, în partea de jos a ferestrei se generează în mod
automat codul SQL. Utilizatorul poate defini obiectul View simultan în mod grafic, cât şi în mod SQL.
86 Baze de date – Introducere în SQL Server

Executarea View-ului se realizează din butonul (Execute SQL) din bara de instrumente, rezultatele
fiind afişate în partea de jos a ecranului.
În fereastra următoare este exemplificat modul de definire a unui View cu grupări, pentru calcularea
numărului de angajaţi care a lucrat la fiecare contract. Activarea grupărilor într-un View se realizează din
butonul (Add Group By) din bara de instrumente.

Figura 4

Crearea/modificarea/ştergerea unui View standard în SQL


Crearea unui obiect View din SQL se realizează folosind sintaxa:

CREATE VIEW numeView As fraza_SQL_SELECTIE

Modificarea unui obiect View din SQL se realizează folosind sintaxa:

ALTER VIEW numeView As


fraza_SQL_SELECTIE

Ştergerea unui obiect View din SQL se realizează folosind sintaxa:


Unitatea de învăţare 4
Interogarea datelor

DROP VIEW numeView

Nota: accesarea unui View dintr-o fraza SQL se realizează respectând sintaxa unei fraze SELECT:

SELECT lista_atribute FROM


NumeView …….
Exemplul 1

Definirea unui View pentru calcularea numărului de angajaţi care a lucrat la fiecare contract.

CREATE VIEW ExempluView


AS
SELECT Contract.NrContract, DataContract,
COUNT(Lucreaza.CNPAngajat) AS NrAng
FROM Contract INNER JOIN Lucreaza ON Contract.NrContract =
Lucreaza.NrContract
GROUP BY Contract.NrContract, Contract.DataContract Exemplul
2 Ştergerea obiectului View creat anterior:

DROP VIEW ExempluView

Crearea unui View indexat in limbajul SQL


Sintaxa simplificată:

CREATE VIEW numeView WITH SCHEMABINDING As fraza_SQL_SELECTIE

CREATE UNIQUE CLUSTERED INDEX numeINDEX ON numeView(numecâmp)

Exemplul 3

Crearea unui View indexat pentru afişarea contractelor din 2008:

CREATE VIEW Exemplu WITH SCHEMABINDING As


SELECT NrContract, DataContract, TarifNegociat
FROM dbo.Contract
WHERE YEAR(DataContract) = 2008 şi apoi:

CREATE UNIQUE CLUSTERED INDEX numeIDX ON


Exemplu(DataContract)
88 Baze de date – Introducere în SQL Server

Crearea unui View partiţionat în SQL


Se implementează cu ajutorul interogărilor de tip UNION, fiind de fapt o reuniune a seturilor de date
cu structură identica/asemănătoare distribuite la nivel local sau pe servere diferite.
Exemplul 1

Definirea unui View distribuit pentru afişarea contractelor încheiate, din două baze de date diferite
(CarteBDA şi CarteBDA_bis), dar care sunt stocate pe acelaşi server.
SELECT NrContract, DataContract, TarifNegociat, CUICl
FROM CarteBDA.dbo.Contract
UNION ALL
SELECT NrContract, DataContract, TarifNegociat, CUICl
FROM CarteBDA_bis.dbo.Contract ORDER BY
DataContract

Exemplul 2

Definirea unui View distribuit pentru afişarea contractelor încheiate, din două baze de date diferite
(CarteBDA şi CarteBDA_server), care sunt stocate pe servere
diferite ([10.1.3.3\CIGTOTAL] şi [FM-PC]) aflate în locaţii geografice diferite.

SELECT NrContract, DataContract, TarifNegociat, CUICl


FROM [10.1.3.3\CIGTOTAL].CarteBDA.dbo.Contract
UNION ALL
SELECT NrContract, DataContract, TarifNegociat, CUICl
FROM [FM-PC].CarteBDA_server.dbo.Contract ORDER BY
DataContract

Notă: pentru a putea executa o frază SQL care foloseşte date de pe mai multe servere se execută în
prealabil procedura sistem (o singura dată pentru fiecare server): sp_addlinkedserver nume_server
Unitatea de învăţare 4
Interogarea datelor
4.3. Proceduri stocate
O procedură stocată este un pachet de instrucţiuni SQL memorat pe server şi compilat la utilizare.
Avantaje:
• Facilitează actualizarea datelor prin faptul că permit ca toate aplicaţiile ce modifică datele să
acţioneze în acelaşi mod;
• Acceptă definirea de parametri şi astfel permit executarea aceloraşi instrucţiuni SQL cu seturi
diferite de parametri;
• Utilizarea procedurilor stocate permite diminuarea fluxului de date în reţea micşorând secvenţele
de cod SQL ce sunt transmise serverului;
• Deoarece planurile de execuţie sunt păstrate de server, performanţele aplicaţiilor pot fi
îmbunătăţite în mod semnificativ.
Utilizarea procedurilor stocate presupune parcurgerea următoarelor etape:
1. Crearea procedurii (prin intermediul comenzii CREATE PROCEDURE)
2. Executarea de către utilizator (prin intermediul unei comenzi EXEC)
3. Compilarea (în timpul unei comenzi EXEC serverul va compila şi optimiza procedura)
4. Executarea de către server (conform planului de execuţie compilat al procedurii)
Pentru a crea o procedură stocată se poate iniţia o nouă interogare în baza de date (New Query) şi se va
utiliza comanda:
CREATE PROCEDURE nume_procedura AS instrucţiuni_SQL Pentru a modifica
o procedură stocată se va utiliza comanda:
ALTER PROCEDURE nume_procedura AS instrucţiuni_SQL

O procedură stocată poate conţine orice instrucţiuni SQL valide cu câteva excepţii dintre care amintim:
CREATE PROCEDURE, CREATE VIEW si CREATE TRIGGER. Sunt însă permise comenzi de tip
CREATE TABLE sau chiar CREATE DATABASE) Procedurile stocate pot fi create prin intermediul
interfeţei oferite de Microsoft SQL Server Management Studio. În cadrul ferestrei Object Explorer,
procedurile stocate pot fi vizualizate în cadrul colecţiei Programmabilty .
90 Baze de date – Introducere în SQL Server

Exemplul: Crearea si lansarea în execuţie a unei proceduri stocate.


Să se realizeze o procedură stocată pentru a obţine lista salariaţilor angajaţi pe parcursul anului 2008.
CREATE PROC ListaAngajati2008 AS
SELECT NumeAng, PrenumeAng, DataAng FROM Angajati
WHERE DataAng BETWEEN ‘1/1/2008’ AND ‘12/31/2008’

Observaţie:
Lansarea în execuţie a procedurii stocate se poate realiza prin simpla specificare a numelui acesteia,
sau prin plasarea instrucţiunii EXEC înaintea numelui procedurii:
EXEC ListaAngajati2008

4.3.1. Proceduri de sistem


Înafara procedurilor definite de utilizatori, SQL server pune la dispoziţia programatorilor o serie de
proceduri predefinite ce sunt memorate în baza de date Master. Aceste proceduri permit executarea
unor rutine utile şi pot fi identificate prin prefixul sp_ ce apare în cadrul denumirii procedurii.

Câteva exemple de astfel de proceduri:

sp_databases permite afisarea listei bazelor de


date de pe server
sp_columns permite afişarea informaţiilor
privind coloanele unui tabel
specificat ca parametru
sp_executesql
permite executarea unor instrucţiuni
SQL specificate ca parametru
sp_help afiseaza toate informaţiile
disponibile privind un anumit obiect
din baza de date

sp_rename permite redenumirea obiectelor din


baza de date
sp_spaceused afişează numărul de înregistrări şi
spaţiul utilizat de un anumit tabel
sau view pe server

4.3.2. Declararea variabilelor


În cadrul procedurilor stocate se pot utiliza variabile pentru a facilita prelucrarea datelor. Variabilele
se declară în cadrul instrucţiunilor ce urmează după cuvântul cheie AS din definiţia procedurii stocate
prin intermediul instrucţiunii DECLARE.
Unitatea de învăţare 4
Interogarea datelor
Numele de variabile sunt precedate de simbolul @ . Atribuirea unei valori se poate realiza prin
instrucţiunile SET sau SELECT. Exemplu – declararea variabilelor
În procedura următoare este utilizată o variabilă de tip numeric @CotaDiscount pentru a calcula
reduceri în procent de 12% la tarifele negociate pentru toate contractele ce au ca obiect ofertele cu
codurile 1 sau 3.

CREATE PROC ReduceriTarife AS


DECLARE @CotaDiscount as numeric(3,2)
SET @CotaDiscount = 0.12
SELECT NrContract, TarifNegociat*@CotaDiscount As Reducere
FROM Contract
WHERE CodOferta=1 OR CodOferta=3

4.3.3. Parametrizarea procedurilor stocate


Parametrii procedurilor SQL Server sunt de tot tipuri:
Parametri de intrare (Input) Parametri de
ieşire (Output)
Parametrii de intrare permit preluarea în cadrul procedurilor stocare a unuia sau mai multor elemente
variabile ce pot fi utilizate în cadrul expresiilor.

Parametri de ieşire sunt utilizaţi pentru returnarea de rezultate în urma prelucrărilor efectuate de
procedura stocată.
O sintaxă simplificată a comenzii CREATE PROCEDURE, care permite şi adăugarea de parametri este
prezentată în continuare:
CREATE PROC nume_procedura
[ [ @parametru tip_de_date] [OUTPUT] [ , ….n] ]
AS
<instrucţiuni SQL>

Procedurile pot utiliza mai mulţi parametri de tip input. Tipul implicit de parametru este cel de intrare.
Doar parametrii însoţiţi de opţiunea OUTPUT, sunt trataţi ca parametri de ieşire şi sunt utilizaţi pentru
a returna valori.
Exemplul - Parametrizarea procedurilor
Să se realizeze o procedură stocată pentru a afişa lista cu numele clienţilor, numerele contractelor şi
tarifele negociate pe o perioadă de timp cuprinsă între două date calendaristice specificate prin
parametri. Se va ordona lista alfabetic, după numele clienţilor.

CREATE PROC ListaContracte


@Data1 as datetime,
92 Baze de date – Introducere în SQL Server

@Data2 as datetime
AS
SELECT DenumireCL, NrContract, TarifNegociat
FROM Contract INNER JOIN Client
ON Contract.CUICl=Client.CUICl
WHERE DataContract BETWEEN @Data1 And @Data2 ORDER BY
DenumireCL

Pentru a lansa în execuţie această procedură trebuie atribuite valori parametrilor. Atribuirea de valori
se poate realiza prin enumerarea valorilor parametrilor in aceeaşi ordine în care au fost declaraţi în
procedură sau prin specificarea exactă a numelui parametrului în faţa fiecărei valori:

EXEC ListaContracte ‘1/1/2007’, ‘1/1/2008’


sau
EXEC ListaContracte @Data1=’1/1/2007’, @Data2=, ‘1/1/2008’
In exemplul precedent, nespecificarea valorii pentru unul dintre cei doi parametri va genera o eroare
şi imposibilitatea de a executa procedura. Pentru a preîntâmpina astfel de situaţii, parametrilor de
intrare li se pot asocia valori implicite, care vor fi utilizate automat atunci când nu se precizează o
altă valoare. Aceste valori se specifică imediat după declararea fiecărui parametru.
Pentru a atribui valoarea implicită ‘1/1/2000’ parametrului @Data1 şi ‘1/1/2009’ parametrului @Data2
se va modifica procedura astfel:

ALTER PROC ListaContracte


@Data1 as datetime = '1/1/2000',
@Data2 as datetime= '1/1/2009'
AS
SELECT DenumireCL, NrContract, TarifNegociat
FROM Contract INNER JOIN Client ON
Contract.CUICl=Client.CUICl
WHERE DataContract BETWEEN @Data1 And @Data2
ORDER BY DenumireCL

După cum se poate observa, întrucât procedura ListaContracte, a fost deja creată şi se dorea doar
modificarea acesteia, s-a utilizat instrucţiunea ALTER în loc de instrucţiunea CREATE.

Exemplu – parametri de tip Output


Pentru a exemplifica utilizarea parametrilor de ieşire vom lua în considerare următoarea situaţie: Se
doreşte calculul unui discount pentru toate contractele nefinalizate. Discountul va fi egal cu 5% din
tariful negociat + 1% din valoarea celui mai mare contract încheiat cu respectivul client.
A. Vom crea o procedura stocată pentru a determina valoarea maximă a contractelor negociate
cu un client. Procedura va conţine un parametru de tip
Unitatea de învăţare 4
Interogarea datelor
OUTPUT care va prelua valoarea salariului maxim calculat şi un parametru de tip INPUT prin care se va
preciza codul clientului.

CREATE PROCEDURE AflaMaximPeClient


@ValMax Money OUTPUT,
@Client as varchar(50)
AS
SELECT @ValMax=MAX(TarifNegociat)
FROM Contract WHERE
CUICl=@Client

B. Pentru a calcula reducerea aferentă fiecărui contract conform algoritmului propus, este
necesar să executăm procedura anterior creată. Valoarea parametrului de tip Output va fi preluată
într-o variabilă de memorie. Pentru parametrul de tip
Input (@client) am ales, pentru exemplificare, valoarea ‘RO1001’, cod aferent unuia dintre clienţi.

DECLARE @Variabila AS money

EXECUTE AflaMaximPeClient
@ValMax=@Variabila OUTPUT, @Client='RO1001'
SELECT NrContract, TarifNegociat*0.05 + @Variabila*0.01 AS
Discount
FROM CONTRACT
WHERE CUICl='RO1001'

4.3.4. Structuri de control al fluxului


 Instrucţiunea RETURN
Prin intermediul comenzii RETURN, se poate forţa întreruperea execuţiei unei proceduri stocate.
Comenzile ce urmează după instrucţiunea RETURN nu vor mai fi executate.
Sintaxa instrucţiunii este: RETURN [ expresie de tip întreg ]

După cum se poate observa, opţional, după instrucţiunea RETURN se poate preciza un număr întreg
ce poate fi utilizat ulterior în cadrul blocului de instrucţiuni ce a lansat în execuţie procedura.
Exemplu:
Să se creeze o procedură stocată pentru a afişa datele unui angajat al cărui CNP este specificat ca
parametru. În cazul în care parametrul nu este specificat (rămâne NULL) se va afişa un mesaj de eroare.

CREATE PROCEDURE AfisezDateAngajat


@cnp char(13) = NULL
AS
IF @cnp IS NULL
BEGIN
94 Baze de date – Introducere în SQL Server

SELECT 'NU ATI FURNIZAT UN CNP !'


RETURN
END
ELSE
SELECT * FROM ANGAJATI WHERE CNP = @cnp

Observaţie:
Orice procedură stocată care se execută cu succes va returna valoarea zero. Procedurile stocate care
provoacă la execuţie o eroare vor returna un cod negativ (de la -1 la -14)

 Structuri alternative de tip IF


Sintaxa:

IF expresie_logica
Bloc_insctructiuni_SQL_1 [ELSE
Bloc_instructiuni_SQL_2]

Un bloc de instructiuni este format dintr-una sau mai multe instrucţiuni:


BEGIN instructiune_1
instructiune_2
….
END

Notă. În cazul în care se execută o singură instrucţiune, cuvintele BEGIN şi END pot să lipsească.
Instrucţiunea IF execută Bloc_insctructiuni_SQL_1 în cazul în care
expresie_logica este adevărată sau Bloc_instructiuni_SQL_2] în cazul în care expresie_logica este falsă.

 Structuri repetitive de tip WHILE


Sintaxa:
WHILE expresie_logica
Bloc_instructiuni_SQL_1 [BREAK]
Bloc_instructiuni_SQL_2 [CONTINUE]
Bloc_instructiuni_SQL_3
Se execută în mod repetat Bloc_instructiuni_SQL_1 atâta timp cât expresie_logica este adevărată. Când
expresie_logica devine falsă, se iese din structura WHILE.
Notă. În cazul în care expresie_logica conţine fraze SQL de tip SELECT, acestea se vor scrie între paranteze
rotunde.
• BREAK realizează ieşirea forţată din WHILE.
Unitatea de învăţare 4
Interogarea datelor
• CONTINUE abandonează iteraţia curentă, toate instrucţiunile de după CONTINUE fiind
ignorate.

 Instrucţiunea WAITFOR

Sintaxa:
WAITFOR DELAY ‘timp_aşteptare’ | TIME ‘ora_execuţie’

Stabileşte un timp de întârziere (timp_aşteptare) până la momentul lansării în execuţie a unei fraze
SQL sau stabileşte ora (ora_execuţie) la care se va lansa în execuţie o frază SQL. Este utilă mai ales la
programarea unor operaţii în perioade timp în care nu se lucrează (de exemplu o operaţie complexă
care nu presupune intervenţia unui utilizator şi se poate executa noaptea). Exemplul 1
Afişarea peste un minut a tuturor contractelor:
WAITFOR DELAY '00:01' SELECT * FROM
Contract

Exemplul 2
Afişarea tuturor angajaţilor la ora 22:48
WAITFOR TIME '22:48'
SELECT * FROM Angajat

Exemplul 3
Se doreşte majorarea treptată cu câte 10% a tarifelor de bază pentru fiecare ofertă, până când media
generală a tarifelor de bază depăşeşte media generală a tarifelor negociate din contracte.
În acest sens, s-a definit codul SQL următor:

--se declara o variabila in care se va memora media


--tarifului negociat din contracte

DECLARE @MedieTarifNegociat as money

--se afiseaza inainte de efectuarea modificarilor


--valorile pentru media tarifului de baza de la oferte
--si media tarifelor negociate ale contractelor

SELECT AVG(TarifBaza) as MedieTarifBazaInitial FROM Oferta


SELECT @MedieTarifNegociat = AVG(TarifNegociat) FROM
Contract
SELECT @MedieTarifNegociat as MedieTarfiNegociat

--Atata timp cat media tarifelor din oferte


--este mai mica decat media tarifelor negociate din
96 Baze de date – Introducere în SQL Server

--contracte se va executa structura repetitiva WHILE

WHILE (SELECT AVG(TarifBaza)


FROM Oferta)<@MedieTarifNegociat
BEGIN
--se majoreaza cu 10% doar tarifele de baza din oferte
--care inca sunt sub media tarifelor negociate din
--contracte
UPDATE Oferta
SET TarifBaza = TarifBaza * 1.1
WHERE TarifBaza < @MedieTarifNegociat

--se afiseaza la fiecare iteratie media tarifelor


-- de baza din oferte
SELECT AVG(TarifBaza) as MedieTarifBaza FROM Oferta END

Rezultatul execuţiei codului de mai sus, este:

Se observă afişarea iniţială a mediei tarifelor de bază (3300) şi a mediei tarifelor negociate
(3675,6139). Apoi se execută două iteraţii, până când media tarifelor de bază din oferte (3730,50)
depăşeşte media tarifelor negociate din contracte (3675,6139).

4.4. Funcţii definite de utilizator


Înafara de setul de funcţii predefinite care au fost prezentate anterior, SQL server permite utilizatorilor
să definească propriile funcţii prin instrucţiuni TRANSACT SQL.
O funcţie SQL, definită de utilizator, grupează în cadrul unui obiect SQL de sine stătător o secvenţă de
instrucţiuni SQL încapsulată, ce poate fi reutilizată ori de câte ori este nevoie.
Funcţiile definite de utilizatori au rolul de a returna un rezultat, calculat conform unui algoritm descris de
utilizator şi pot utiliza parametri în cadrul calculelor.
În funcţie de tipul de rezultat returnat, funcţiile definite de utilizatori pot fi clasificate în două categorii:
 Funcţii de tip scalar (scalar functions) – care returnează o valoare ce poate fi încadrată în unul
dintre tipurile de date SQL Server (de exemplu char, varchar, numeric, datetime, etc.)
 Funcţii de tip tabelar (table valued functions) – care returnează un set de înregistrări ce poate
fi asimilat unui tabel virtual.
Unitatea de învăţare 4
Interogarea datelor
Dintre avantajele aduse de utilizarea funcţiilor putem menţiona:
 Funcţiile definite de utilizator oferă posibilitatea de a structura într-o manieră eficientă codul SQL
şi pot simplifica prelucrările de date ce implică realizarea unor structuri complexe de programare.
 O dată create, funcţiile pot fi utilizate în cadrul obiectelor de tip View sau al procedurilor stocate,
diminuând considerabil dimensiunea codului SQL şi facilitând o mai bună structurare a acestuia.
 Funcţiile de tip table valued functions pot fi utilizate pentru simularea unor tabele virtuale extrem
de utile în programarea procedurilor.

Funcţii de tip scalar (scalar functions)

O funcţie de tip scalar poate accepta zero sau mai mulţi parametri şi va returna o singură valoare.
Pentru a crea o astfel de funcţii se va utiliza comanda CREATE FUNCTION a cărei sintaxă
simplificată este următoarea:

CREATE FUNCTION [numeproprietar.] nume_funcţie


([ @parametru_1 AS tip_de_date],
…. [ @parametrul_n AS tip_de_date] )
RETURNS tip_de date
AS
BEGIN
INSTRUCŢIUNI SQL
RETURN valoare de returnat END

Pentru modificarea unei funcţii se utilizează sintaxa:


ALTER FUNCTION

Pentru ştergerea unei funcţii se utilizează sintaxa:


DROP FUNCTION

Observaţii:
 Prin intermediul instrucţiunii RETURNS se precizează tipul de date al valorii returnate de funcţie.
 Prin intermediul instrucţiunii RETURN se specifică efectiv valoare de returnat rezultată în urma
calculelor din comenzile SQL precizate în corpul funcţiei (între BEGIN şi END). În corpul funcţiei, între
BEGIN şi END pot fi incluse structuri repetitive, declaraţii de variabile, etc. Valoarea returnată nu
poate fi de tip tabel, motiv pentru care nu pot fi utilizate în clauza FROM a unei instrucţiuni SELECT,
însă pot fi utilizate în SELECT, WHERE, GROUP BY, HAVING şi ORDER BY.
 Numele complet al unei funcţii este dat de următorul specificator:
98 Baze de date – Introducere în SQL Server

NumeBazaDate.NumeProprietarFunctie.NumeFuncţie

La apelarea unei funcţii definite de utilizator dintr-o frază SQL, trebuie precizat în mod obligatoriu
proprietarul funcţiei (de exemplu dbo). Numele bazei de date se precizează doar dacă funcţia
executată provine din altă bază decât cea unde se face apelul către ea. În cazul în care funcţia trebuie
executată de alt utilizator decât proprietarul, acesta trebuie să aibă dreptul de EXECUTE asupra
acesteia.
Informaţii despre o funcţie se pot obţine folosind următoarea procedură de sistem: sp_help funcţie

Exemplul 1

Se dau de la două dintre tabelele din modelul proiectat în primul capitiol al cărţii.

CLIENTI (CUICl, DenumireCL, AdresaCL, LocalitateCl, TaraCL )


CONTRACTE(NrContract, DataContract, DataFinContract, TarifNegociat , CodClient) Se doreşte
realizarea unei funcţii pentru calculul unui discount ce se aplica la valoarea contractelor (tariful
negociat) după următoarele criterii:
 Pentru contractele de la clienţii din afara României cu valoare sub 1000 se aplica 5 % la valoare
contract
 Pentru contractele de la clienţii din afara României cu valoare peste 1000 se aplica 7% la valoare
contract
 Pentru contractele de la clienţii din România se aplica 10% la valoare contract
CREATE FUNCTION DISCOUNT(@VALC AS MONEY,
@TARA AS VARCHAR(50))
RETURNS money
AS
BEGIN

RETURN
CASE
WHEN @TARA<>'Romania' AND @VALC<1000 THEN @VALC*0.05
WHEN @TARA<>'Romania' AND @VALC>=1000 THEN @VALC*0.07
ELSE @VALC*0.1
END
END

Ulterior putem utiliza funcţia în cadrul unui View după cum se poate observa în figura următoare:
Unitatea de învăţare 4
Interogarea datelor

Figura 5 Utilizarea funcţiei definite în cadrul unui View


Observaţie: Funcţiile de tip Scalar se pot utiliza şi în cadrul procedurilor stocate, cel mai uzual în cadrul
clauzei SELECT pentru definirea expresiilor, dar şi în cadrul clauzei WHERE pentru a impune restricţii.

Exemplul 2

Se doreşte să se realizeze o funcţie pentru a calcula pentru fiecare dintre clienţii cu care nu mai sunt
contracte în derulare în prezent câte săptămâni au trecut de la finalizarea ultimului contract.
Pentru clienţii la care încă se mai lucrează la ultimul contract (nu s-a ajuns la data de finalizare) funcţia va
returna valoarea 0.

CREATE FUNCTION CalculSaptamani (@CodC as char(30))


RETURNS int
AS
BEGIN
DECLARE @UltimaData as datetime
SET @UltimaData = (SELECT max(DataFinContract)
FROM CONTRACT
WHERE CUICl=@CodC)
RETURN
CASE
WHEN @UltimaData>=GETDATE() THEN 0
ELSE Datediff(week, @UltimaData, getdate())
END
END

Ulterior putem utiliza funcţia în cadrul unei proceduri stocate. În exemplul următor se vor selecta
clienţii români cu care nu s-a mai colaborat de mai mult de 10 saptamani
100 Baze de date – Introducere în SQL Server

SELECT CUICl, DenumireCl, LocalitateCl, TaraCl , dbo.Ex2(CUICl)


as [saptamani de la ultimul contract]
FROM CLIENT
WHERE dbo.Ex2(CUICl)>10 And TaraCl='Romania'

Exemplul 3

Se doreşte alocarea unor coduri contractelor pentru realizarea unor clasificări şi verificări ulterioare.
Codurile vor fi alcătuite din: primele 3 caractere din denumirea ţării din care provine clientul, urmate
de caracterul de pe poziţia a doua din numele clientului, apoi, ultimele doua cifre din anul în care s-a
semnat contractul şi numărul zilei din an în care s-a finalizat contractul.

CREATE FUNCTION Codificare(@Tara as varchar(50), @NumeC As


varchar(50), @DataC as datetime, @DataF as datetime)
RETURNS char(9)
AS
BEGIN
--- OBSERVATIE:
--- ESTE NECESAR CA DATELE DE TIP NUMERIC SI CALENDARISTIC
--- SA FIE CONVERITE IN TIMP SIR DE CARACTERE

DECLARE @Cod1 as char(3) --prima parte din cod (tara)


DECLARE @Cod2 as char(1) --a doua parte din cod (client)
DECLARE @Cod3 as char(2) --a treia parte din cod (anul)
DECLARE @Cod4 as char(3)--a patra parte din cod (ziua)

SET @Cod1= LEFT(@TARA,3)


SET @Cod2 = SUBSTRING( @NumeC,2,1)
SET @Cod3= RIGHT( CONVERT(CHAR(4), YEAR(@DataC)) , 2)
SET @Cod4 = CONVERT (CHAR(3), DATEPART(dayofyear, @DataF))

RETURN @COD1+@COD2+@COD3+@COD4

END
Utilizarea funcţiei pentru a afişa lista codurilor aferente contractelor este exemplificată în interogarea
următoare:

SELECT NrContract, DenumireCl, TaraCl,


DataContract,DataFinContract, dbo.Codificare(TaraCl,
DenumireCl, DataContract, DataFinContract) As Cod
FROM Client INNER Join Contract on
Client.Codclient=Contract.CodClient
Unitatea de învăţare 4
Interogarea datelor

Funcţii de tip tabelar (table valued functions)


Funcţiile de tip tabelar se diferenţiază de cele de tip scalar prin faptul că returnează un set de date sub
forma unui tabel bidimensional conform modelului relaţional.
Având în vedere faptul că sunt asimilate tabelelor (virtuale), pot fi utilizate în cadrul unei fraze SQL,
similar modului cum sunt utilizate tabelele bazei de date. Datele rezultate nu sunt memorate sub
forma unui tabel în baza de date, ci sunt obţinute dinamic la fiecare apel al funcţiei – similar obiectelor
de tip View. Diferenţa majoră faţă de acestea constă în posibilitatea utilizării parametrilor în cadrul
funcţiilor, conferindu-le un grad ridicat de flexibilitate.

Aceste funcţii sunt utilizate în clauza FROM a interogărilor.

Sintaxa simplificată pentru definirea unei funcţii de tip tabelar este următoarea:
A). (varianta INLINE) funcţia returnează un tabel ca rezultat, fără a fi nevoie să se definească
structura acestuia. În această varianta nu sunt permise BEGIN ….END, ci doar o frază SQL de tip SELECT,
rezultatele fiind furnizate sub forma unui tabel. Fiecare câmp din interogarea sursă trebuie să aibă un
nume, ceea ce înseamnă că expresiile cu mai mulţi operanzi trebuie sa aibă neapărat un alias. În
această variantă de utilizare, utilizarea clauzei ORDER BY este permisă numai dacă se utilizează
împreună cu TOP în instrucţiunea SELECT. Nu sunt permise prelucrări complexe.
CREATE FUNCTION [numeproprietar.] nume_funcţie
([ @parametru_1 AS tip_de_date],
… [ @parametrul_n AS tip_de_date] )
RETURNS TABLE
As
RETURN (fraza_SQL_SELECT)

Exemplu

Realizaţi o funcţie prin intermediul căreia să se determine care sunt primii 10 clienţi cu cele mai multe
contracte. Funcţia va returna codurile clienţilor şi numărul total de contracte.

CREATE FUNCTION CLIENTI_IMPORTANTI()


RETURNS TABLE
AS
RETURN (SELECT top 10 CUICl, COUNT(NrContract)
FROM CONTRACT
GROUP BY CUICl
ORDER BY COUNT(NrContract) DESC)

B). varianta (MULTIINSTRUCŢIUNE). Funcţia va returna un tabel rezultat, fiind necesară şi


definirea structurii acestuia. Faţă de varianta A, această categorie poate să includă prelucrări
complexe.
CREATE FUNCTION [numeproprietar.] nume_funcţie ([
@parametru_1 AS tip_de_date],
…. [ @parametrul_n AS tip_de_date] )
102 Baze de date – Introducere în SQL Server

RETURNS @variabila_output TABLE (câmp_1


tip de date, … câmp_N tip de date)
AS
BEGIN
INSTRUCŢIUNI SQL
RETURN
END

Exemplu

Realizaţi o funcţie prin intermediul căreia să se determine care sunt primii 10 clienţi cu cele mai multe
contracte. Funcţia va returna codurile clienţilor şi numărul total de contracte.

CREATE FUNCTION CLIENTI_IMPORTANTI()


RETURNS @Tabel_10 TABLE
(CodC AS varchar(30), TotalContracte AS int)
AS
BEGIN
INSERT @Tabel_10
SELECT top 10 CUICl, COUNT(NrContract)
FROM CONTRACT
GROUP BY CUICl
ORDER BY COUNT(NrContract) DESC

RETURN
END

Putem utiliza funcţia în cadrul unei proceduri stocate ce afişează lista contractelor cu clienţii importanţi,
contractate de la începutul anului 2008 astfel:

SELECT NrContract, DataContract, TarifNegociat,


DenumireCl, AdresaCl
FROM CONTRACT INNER JOIN CLIENT ON
Contracte.CodClient=Clienti.Codclient
WHERE CLIENTI.CodClient IN (SELECT CodClient FROM
dbo.CLIENTI_IMPORTANTI() ) AND
DataContract>'1/1/2008'

După cum se poate observa, funcţia precedentă nu a necesitat parametri. Pentru exemplificarea
unei funcţii cu parametri vom rezolva exemplul următor:
Unitatea de învăţare 4
Interogarea datelor
Exemplu
Se doreşte realizarea unei funcţii care să returneze lista contractelor finalizate întro anumită perioadă
şi, pentru fiecare dintre acestea, 50% din valoarea contractata (tariful negociat).

Ulterior se va realiza o procedură stocată pentru a calcula totalul încasărilor din finalizarea contractelor
de la un anumit client pe o perioadă de timp (presupunem că la finalizarea contractelor se încasează
50% din valoarea contractată)
1. Realizarea funcţiei

CREATE FUNCTION ListaFinalizari (@Data1 as datetime,


@Data2 As Datetime)
RETURNS @ListaF TABLE
(NrContract int,
DataFinalizare datetime,
CodClient varchar(30),
Incasari money)
AS
BEGIN
INSERT @ListaF
SELECT NrContract, DataFinContract,
CUICL, TarifNegociat/2
FROM CONTRACT
WHERE DataFinContract BETWEEN @Data1 AND @Data2

RETURN
END

2. Realizarea procedurii stocate:


CREATE PROC Incasari_Final_Contract
@CodC AS varchar(30),
@DataStart AS DateTime,
@DataSfarsit AS DateTime
AS
SELECT CodClient, SUM(Incasari)
FROM ListaFinalizari(@DataStart, @DataSfarsit)
WHERE CodClient=@CodC
GROUP BY Codclient

Lansarea în execuţie a procedurii stocate pentru a determina încasările de la clientul cu codul RO1000 în
intervalul 2 iunie 2007 – 3 mai 2008:

EXEC Incasari_Final_Contract ‘RO1000’, '2/6/2007', '3/5/2008'


104 Baze de date – Introducere în SQL Server

4.5. Utilizarea cursoarelor


Cursoarele SQL reprezintă o modalitate de parcurgere secvenţială a unui set de înregistrări returnat de o
frază SQL de tip SELECT.

Instrucţiuni pentru declararea şi utilizarea cursoarelor:


a. Declararea cursoarelor se realizează cu instrucţiunea:

DECLARE nume_cursor CURSOR


[ FORWARD_ONLY | SCROLL ]
[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]
[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]
FOR instructiune_SQL_SELECT
[ FOR UPDATE [ OF nume_coloana [ ,...n ] ] ]

 FORWARD_ONLY – permite deplasarea numai în modul “înainte” în cadrul înregistrărilor cursorului.

 SCROLL – permite operaţiile FIRST, LAST, PRIOR, NEXT, RELATIVE,


ABSOLUTE pentru deplasarea în cadrul înregistrărilor cursorului.

 STATIC – determină realizarea unei copii temporare a setului de înregistrări pe care se lucrează.
În cazul în care se fac modificări în tabelele folosite ca sursă de către cursor, acestea nu se reflectă
în cadrul setului de înregistrări virtual, asociat cursorului. Cursorul nu este actualizabil.
 DYNAMIC – permite ca orice modificare efectuată în tabelele sursă ale cursorului să se reflecte
automat în setul de înregistrări asociat acestuia. În acest tip de cursor nu se poate utiliza deplasarea
prin instrucţiunea ABSOLUTE.

 KEYSET – specifică faptul că înregistrările din cursor sunt deschise într-o anumită ordine.
 FAST_FORWARD – se utilizează pentru a optimiza accesul la înregistrările cursorului (numai
“înainte”).
 SCROLL_LOCKS – blochează înregistrările care se citesc (pentru ceilalţi utilizatori), în aşa fel încât
orice actualizare încercată pe înregistrările citite să se efectueze cu succes.
 OPTIMISTIC – nu blochează înregistrările citite, însă în cazul în care alţi utilizatori efectuează
actualizări pe aceleaşi înregistrări cu cele din cursor, iar cel care utilizează cursorul încearcă şi el
modificări, se citeşte valoarea coloanei timestamp, iar în cazul în care se detectează că s-au efectuat
actualizări de către alţi utilizatori, atunci actualizarea iniţiată în cursor va eşua.  READ ONLY – nu
sunt permise modificările/ştergerile în cadrul înregistrărilor cursorului.
 UPDATE [OF nume_coloana [ ,...n ] ] ] – stabileşte o coloană sau mai multe coloane pe care se pot
face actualizări în cadrul înregistrărilor cursorului.

Observaţie: În fraza SQL de selecţie nu sunt permise clauzele COMPUTE, COMPUTE BY şi INTO. b.
OPEN nume_cursor
Unitatea de învăţare 4
Interogarea datelor
Execută instrucţiunile T-SQL declarate în cursor şi încarcă în memorie setul de înregistrări rezultat.
c. CLOSE nume_cursor
Închide cursorul, orice blocaje induse de acesta înregistrărilor din tabelele folosite de cursor fiind şterse.
d. DEALLOCATE nume_cursor
Eliberează memoria ocupata de cursor.

e. Instrucţiunea FETCH
Accesează o înregistrare din cursor. Sintaxa:

FETCH
[ [ NEXT | PRIOR | FIRST | LAST
| ABSOLUTE { n | @nvar }
| RELATIVE { n | @nvar } ]
FROM
]
Nume_cursor
[ INTO @variable_name [ ,...n ] ]

 ABSOLUTE { n | @nvar}
• dacă n este un număr pozitiv se returnează înregistrarea cu numărul n, calculată în raport cu
începutul cursorului.
• dacă n este un număr negativ se returnează înregistrarea cu numărul n, calculată în raport cu
sfârşitul cursorului.

[ INTO @variable_name [ ,...n ] ]


Se specifică un set de variabile în care se vor încărca valorile din coloanele rândului accesat din cursor.
Variabilele se vor preciza în aceeaşi ordine ca şi câmpurile din cadrul cursorului.

f. Variabila @@FETCH_STATUS
Determina daca mai exista înregistrări de accesat in cursor. Valori posibile:
• 0 – instrucţiunea FETCH pentru accesarea unei înregistrări s-a executat cu succes.
• -1 – instrucţiunea FETCH pentru accesarea unei înregistrări a eşuat.
• -2 – instrucţiunea FETCH pentru accesarea unei înregistrări nu a returnat niciun rezultat.

Exemplu

Sa se definească o procedură stocată care să folosească un cursor pentru următoarele operaţii:


106 Baze de date – Introducere în SQL Server

• parcurgerea unui set de înregistrări virtuale, secvenţial, înainte, cu media tarifelor negociate ale
fiecărei oferte folosite în contracte.
• daca media tarifelor negociate a unei oferte din cursor este mai mare decât o valoarea transmisă
printr-un parametru procedurii stocate se va majora cu
10% tariful de bază al ofertei (în tabelul Oferta).

CREATE PROCEDURE TestCursor


@pParametru as money
AS

--se declara cursorul


--Atentie ! Nu se executa inca fraza SQL asociata

DECLARE cursorExemplu CURSOR STATIC SCROLL


FOR SELECT CodOferta, AVG(TarifNegociat) as Medie
FROM Contract
GROUP BY CodOferta

--se declara doua variabile in care se vor incarca


--cele doua coloane ale cursorului
declare @pCodOferta as bigint, @pMedie as money

--urmatoarea fraza SQL este numai pentru control/test


--pentru a urmari ce se executa in fereastra Results
SELECT CodOferta, AVG(TarifNegociat) as Medie
FROM Contract
GROUP BY CodOferta

--urmatoarea fraza este tot pentru test pentru


--a urmari valorile initiale ale preturilor de catalog
--si sa putem observa la sfarsit daca s-au produs
--modificari in baza de date
SELECT * FROM Oferta

--se executa fraza SQL din cursor


OPEN cursorExemplu

--se pozitioneaza pe prima inregistrare din cursor


FETCH NEXT FROM cursorExemplu

--se incarca cele doua variabile cu


--valorile din coloanele cursorului
INTO @pCodOferta, @pMedie
Unitatea de învăţare 4
Interogarea datelor
--in cazul in care exista cel putin o inregistrare
--se incearca parcurgerea intregului cursor atata timp
--cat o intructiune FETCH returneaza in variabila
--@@FETCH_STATUS valoarea zero
--Prima data instructiunea WHILE de mai jos verifica
--starea instructiunii FETCH executata anterior
WHILE @@FETCH_STATUS = 0
BEGIN
IF @pMedie>@pParametru
BEGIN
UPDATE Oferta SET TarifBaza = TarifBaza * 1.1
WHERE CodOferta = @pCodOferta
END

--se pozitioneaza pe urmatoarea inregistrare din cursor


FETCH NEXT FROM cursorExemplu
INTO @pCodOferta, @pMedie
END

--urmatoarea fraza SQL este pentru test


--pentru a urmari daca s-au efectuat modificari
SELECT * FROM Oferta

--se inchide cursorul


CLOSE cursorExemplu

--se elibereaza memoria


DEALLOCATE cursorExemplu

Apelul procedurii stocate cu parametrul 4000 (se vor lua în considerare din cursor doar mediile tarifelor
de bază mai mari de 4000):

EXEC TestCursor 4000

În captura de mai jos se vede rezultatul execuţiei prin urmarirea înregistrărilor returnate de cele trei fraze
SQL de test, incluse în procedura stocată:
• În primul set de rezultate se observă ofertele care au media tarifelor negociate mai mari de 4000
(ofertele cu codul 2 şi 4).
• În al doilea set de rezultate se observă valorile iniţiale ale tarifelor de bază pentru cele două oferte
(ofertele cu codul 2 şi 4).
• În al treilea set de rezultate se observă valorile finale ale tarifelor de bază pentru cele două oferte
(ofertele cu codul 2 şi 4).
108 Baze de date – Introducere în SQL Server

4.6. Exerciţii propuse şi rezolvate


Se vor lua în considerare două dintre tabelele bazei de date pentru evidenţa clienţilor şi contractelor
proiectată în primul capitol al cărţii la care a fost adăugat şi un tabel pentru evidenţa încasărilor (pentru
fiecare contract pot exista mai multe ordine de plată memorate în tabelul Incasari).
Se dau de la două dintre tabelele din modelul proiectat în primul capitiol al cărţii.
CLIENT(CUICl, DenumireCL, AdresaCL, LocalitateCl, TaraCL )
CONTRACT(NrContract, DataContract, DataFinContract, TarifNegociat , CUICl) INCASARI
(CodIncasare, NrOP, DataOP, Suma, NrContract)

1. Realizaţi un trigger pe tabelul Încasări, pentru operaţia de ştergere, astfel încât să nu se poată şterge
încasările ce provin din contracte finalizate in anul 2007.
Rezolvare
CREATE TRIGGER NuSterge2007 ON Incasari for DELETE
AS
IF EXISTS(SELECT NrContract
FROM DELETED
WHERE NrCONTRACT IN (SELECT NrContract
FROM CONTRACT
WHERE YEAR(DataFinContract)=2007))
Unitatea de învăţare 4
Interogarea datelor
BEGIN
RAISERROR ('Nu se poate şterge', 18,1)
ROLLBACK TRANSACTION
END

2. Realizaţi un View pentru a calcula totalul încasărilor din anul 2007 pe fiecare client. Pentru
clienţii la care totalul încasărilor depăşeşte 40000 se va calcula un BONUS de 2% din total încasări.

Figura 6 View

3. Realizaţi o funcţie de tip scalar ce va calcula pe fiecare contract un coeficient de importanţa în


funcţie de valoarea contractului şi de anul in care a fost incheiat contractul astfel:
• pentru contractele din anul 2007 cu valoare peste 60.000  coeficient 1
• pentru contractele din anul 2007 cu valoare sub 60.000  coeficient 2
• pentru contractele de dinainte de 2007  coeficient 3
Rezolvare
CREATE FUNCTION Coeficient(@datac as datetime, @Valoare as money)
RETURNS INTEGER
AS
BEGIN
RETURN
CASE
WHEN YEAR(@DATAC)= 2007 AND @VALOARE >=60000
THEN 1
WHEN YEAR(@DATAC)= 2007 AND @VALOARE <60000
THEN 2
ELSE 3
END
END
Exemplu de utilizare:
SELECT NrContract, DataContract, TarifNegociat,
dbo.Cerinta4(DataContract, TarifNegociat)
FROM CONTRACT
110 Baze de date – Introducere în SQL Server

4. Realizaţi o funcţie de tip tabelar care sa returneze numerele de contracte şi numele clientilor pentru
contractele dintr-un anumit an (anul va fi specifcat ca argument al functiei).
Rezolvare
CREATE FUNCTION ListaPeAn (@An as integer)
RETURNS @Tabel TABLE
(NrContract Integer, Client varchar(50) )
AS
BEGIN
INSERT @Tabel
SELECT NrContract, DenumireCl
FROM CLIENT INNER JOIN CONTRACT ON
CLIENT.CUICl=CONTRACT.CUICl
WHERE YEAR(DataContract)= @an

RETURN
END
Exemplu de utilizare:
SELECT * FROM ListaPeAn(2006)

5. Realizaţi o procedura stocată cu parametri pentru a realiza un clasament al clienţilor in funcţie de


valoarea totală a contractelor. Se va utiliza funcţia RANK sau ROW_NUMBER. Procedura va fi
parametrizată pentru nu a afişa decât clienţii a căror valoare totala a contractelor depăşeşte o sumă
specificată prin parametru.

CREATE PROC Clasament


@Suma as money
AS
SELECT DenumireCl, SUM(TarifNegociat) AS TOTAL,
RANK() OVER ( ORDER BY SUM(TarifNegociat) DESC)
FROM CLIENT INNER JOIN CONTRACT
ON CLIENT.CUICL= CONTRACT.CUICL
GROUP BY DenumireCl
HAVING SUM(TarifNegociat)>@Suma

Exemplu de utilizare:
EXEC Clasament 6000
6. Realizaţi o procedură stocată pentru a a afişa o listă a contractelor încheiate între două date
calendaristice specificate prin parametri. Lista va conţine: NrContract, DataContract, DenumireCl şi
LocalitateCL. Se va calcula câte contracte a încheiat firma, în respectiva perioadă, în fiecare localitate.
Rezolvare
CREATE PROC ListaContractelor
@DataInceput AS Date,
@DataSfarsit AS Date
AS
Unitatea de învăţare 4
Interogarea datelor
SELECT NrContract, DataContract, DenumireCl,
LocalitateCL
FROM CLIENT INNER JOIN CONTRACT
ON CLIENT.CUICL= CONTRACT.CUICL
WHERE DataContract BETWEEN @DataInceput AND @DataSfarsit AS Date
ORDER BY LocalitateCL
COMPUTE COUNT(NrContract) ON LocalitateCl

7. Realizaţi o procedură stocată pentru a majora tarifele negociate cu un anumit procent precizat ca
parametru. Doar pentru contractele nefinalizate până la data curentă.
Rezolvare
CREATE PROC Majorare
@Procent AS numeric(3,2)
AS
UPDATE CONTRACT
SET TarifNegociat= TarifNegociat*(1+@Procent)
WHERE DataFinContract>GETDATE()

8. Sa se parcurga prin intermediul unui cursor tabelul Incasari in ordine cronologica a datelor de pe
ordinele de plată şi să se determine la ce dată s-a atins plafonul de 50.000 de RON încasări totale.

DECLARE CRS CURSOR FORWARD_ONLY STATIC


FOR
SELECT DataOP, Suma
FROM Incasari
ORDER BY DataOP

DECLARE @DataPlafon AS DateTime


DECLARE @incasare AS money
DECLARE @Cumulat As money

OPEN CRS

-- citim prima inregistrare din cursor FETCH NEXT From


CursorEx1
INTO @DataPlafon, @incasare
SET @CUMULAT=@incasare

-- se aduna sume in variabila cumulat pana se atinge –


-- plafonul sau pana se ajunge la sfarsitul setului de inregistari
WHILE @@FETCH_STATUS=0
BEGIN
IF @Cumulat>10000 BREAK
FETCH NEXT From CursorEx1
112 Baze de date – Introducere în SQL Server

INTO @DataPlafon, @Suma


SET @CUMULAT=@CUMULAT+@incasat
END

--se afiseaza data la care s+a atins plafonul


--si suma cumulata
SELECT @DataPlafon As [Data plafon], @Cumulat AS [suma la aceasta
data]

CLOSE CRS
DEALLOCATE CRS

? Întrebări

1. Ce este un obiect de tip view?


2. Ce este o procedură stocată şi de câte feluri sunt ?
3. Cum se crează o funcţie definite de utilizator (paşi de lucru)?

Bibliografie Unitatea de învăţare 4

1. SQL Server 2014 Development Essentials, Design, implement and deliver a successful database
solution with Microsoft SQL Server 2014, Basit A Masood al Farooq, Publicat Packt Publishing Ltd.,
Livery Place, 2014;
2. Baze de date – Access 2007, proiectare şi realizare pas cu pas, Tamaş Ilie, Stanciu Victoria,
Gheorghe Mirela, Mareş Valerica, Mangiuc D, Editura Infomega, Bucureşti, 2010.

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