Documente Academic
Documente Profesional
Documente Cultură
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
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.
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:
Exemplul 3
Exemplul 4
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ţia DAY
Returnează ziua dintr-o dată calendaristică. Sintaxa:
DAY (expresie)
Funcţia MONTH
MONTH(expresie)
Funcţia YEAR
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.
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
Sintaxa:
LTRIM(expresie)
Funcţia LEN
Sintaxa:
LEN(expresie)
Funcţia LOWER
74 Baze de date – Introducere în SQL Server
Sintaxa:
LOWER(expresie)
Funcţia UPPER
Sintaxa:
UPPER(expresie)
Exemplu
Funcţia LEFT
Sintaxa:
LEFT(expresie, n)
Funcţia RIGHT
Sintaxa:
RIGHT(expresie, n)
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
Funcţia POWER
Returnează valoarea unui număr ridicat la o putere.
Sintaxa
POWER(expresie numerică,puterea)
Exemplu:
Funcţia ABS
Funcţia SIGN
Sunt funcţii utilizate pentru rotunjirea valorilor numerice. Diferenţele dintre aceste funcţii sunt redate în
exemplul următor:
• 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:
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
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 > )
Î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 > )
• 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.
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:
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;
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;
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):
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
Nota: accesarea unui View dintr-o fraza SQL se realizează respectând sintaxa unei fraze SELECT:
Definirea unui View pentru calcularea numărului de angajaţi care a lucrat la fiecare contract.
Exemplul 3
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.
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
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
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.
@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:
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.
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.
EXECUTE AflaMaximPeClient
@ValMax=@Variabila OUTPUT, @Client='RO1001'
SELECT NrContract, TarifNegociat*0.05 + @Variabila*0.01 AS
Discount
FROM CONTRACT
WHERE CUICl='RO1001'
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.
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)
IF expresie_logica
Bloc_insctructiuni_SQL_1 [ELSE
Bloc_instructiuni_SQL_2]
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ă.
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 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).
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:
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.
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
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.
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
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.
RETURN @COD1+@COD2+@COD3+@COD4
END
Utilizarea funcţiei pentru a afişa lista codurilor aferente contractelor este exemplificată în interogarea
următoare:
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.
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.
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:
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
RETURN
END
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:
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.
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
• 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).
Apelul procedurii stocate cu parametrul 4000 (se vor lua în considerare din cursor doar mediile tarifelor
de bază mai mari de 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
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
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)
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.
OPEN CRS
CLOSE CRS
DEALLOCATE CRS
? Întrebări
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.