Sunteți pe pagina 1din 86

Training

SQL Querying pentru Business

Version: 5 / septembrie 2020

1
Contents

Training .................................................................................................................................................. 1
SQL Querying pentru Business .............................................................................................................. 1
I. Notiuni Generale ................................................................................................................................. 3
II. Structura informatiei dintr-un DBMS relational .................................................................................. 5
III. SQL Data Types ............................................................................................................................... 7
IV. Setul de comenzi T-SQL: SELECT si FROM ..................................................................................... 13
V. Setul de comenzi T-SQL: Filtrare si Sortare Date ............................................................................... 24
VI. Setul de comenzi T-SQL: Grupare si Agregare date ....................................................................... 34
VII. Utilizare JOIN. Tipuri de JOIN ........................................................................................................ 39
VIII. Setul de comenzi T-SQL: CASE, COALESCE, ISNULL ....................................................................... 42
IX. Functii de data si ora: YEAR, MONTH, DAY, DATEDIFF, DATEADD................................................. 45
X. Functii de text: CHARINDEX, SUBSTRING, LEN. Operatorul de concatenare ..................................... 48
XI. Tabele temporare. CTE ................................................................................................................. 52
XII. Utilizare operatorilor pentru seturi de date: UNION ALL, UNION, INTERSECT, EXCEPT ................ 57
XIII. Creare baza de date. Creare tabele. Constrangeri tabele. Diagrama baza de date. ...................... 62
XIV. Setul de comenzi T-SQL: INSERT, UPDATE, DELETE, TRUNCATE .................................................... 74
XV. Creare VIEW-uri ............................................................................................................................ 82

2
I. Notiuni Generale

O baza de date reprezinta un ansamblu de date, organizat coerent, structurat cu o redundanta


minima si accesibile cat mai multor utilizatori in acelasi timp. Toate aceste date sunt organizare
in tabele. Cel mai utilizate tipuri de baze de date sunt cele relationale, in care informatiile sunt
organizate in mai multe tabele intre care exista legaturi (relatii).

Pentru a putea defini structura unei baze de date si a stoca informatiile avem nevoie de un
software care sa realizeze toate functiile pe care aceste nevoi le implica. Un astfel de soft se
numeste sistem de gestiune a bazelor de date, prescurtat in romana SGBD si in engleza
DBMS (Database Management System).

Un DBMS implementeaza functiile necesare pentru diferitele aspecte ale lucrului cu bazele de
date:

- Memorarea fizica a datelor intr-un format optimizat in vederea viitoarelor


prelucrari/manipulari
- Definirea si modificarea structurii bazelor de date
- Introducerea informatiilor noi si manipularea celor existente
- Restrictionarea accesului la datele memorate (un sistem de privilegii care sa faca
distinctie intre diversi utilizatori/clienti/aplicatii)
- Implementarea unei modalitati de acces la toate aceste facilitati.

Accesarea informatiilor dintr-o baza de date se poate realiza de catre un utilizator (un profesor
insereaza notele de la examen) sau de catre o aplicatie (o aplicatie de monitorizare a unui
server web insereaza intr-o baza de date paginile accesate, tipul de browser folosit).

Utilizatorul interfateaza cu DBMS prin intermediul unui client – o aplicatie (SQL Server
Management Studio).

Aplicatiile care acceseaza bazele de date o fac indirect, prin intermediul DBMS. Atunci cand
dorim, spre exemplu, sa cream o baza de date sau sa inseram informatii in baza de date , vom
solicita softului DBMS sa faca acest lucru, trimitand comenzile corespunzatoare. DBMS
cunoaste formatul in care a fost memorata informatia si are acces direct la datele in cauza.
Aplicatia client nu poate avea intotdeauna acces la date (deseori clientii ruland pe alta masina

3
decat DBMS. Clientul acceseaza datele independent de aspectele fizice ale stocarii datelor pe
HDD sau in RAM.

Avand in vedere ca DBMS ofera servicii clientilor in baza cererilor formulate de catre acestia, el
contine un modul care actioneaza ca server de baze de date.

Cererea trimisa de catre clienti serverului de baze de date poarta denumirea de interogare
(query).

Unul dintre beneficiile importante pe care le ofera un DBMS este decuplarea modalitatii fizice de
structurare a datelor (exemplu: organizarea, locatia si denumirea fisierelor) de modalitatea de
accesare si manipulare a lor. Utilizatorul care beneficiaza de serviciile unui DBMS nu vede (si
nici nu doreste sa stie) aspectele low-level ale stocarii informatiei, ci doreste o viziune logica a
datelor memorate care sa ii permita usoara lor introducere, extragere si prelucrare.

In acest scop, DBMS pune la dispozitia utilizatorului fie o interfata grafica, fie un limbaj care sa ii
permita acestuia interactiunea cu datele si facilitatile conexe acestora. Limbajul folosit in cazul
bazelor de date relationale este SQL (Sructured Query Language).

SQL este un limbaj ce contine intructiuni pentru definirea si modificarea structurii bazelor de
date, accesarea si manipularea datelor si controlul accesului la date. El a fost creat la inceputul
anilor ”70 la IBM si folosit initial ca baza intr-unul dintre produsele acestei firme. Ulterior, in
1986, el este standardizat de catre ANSI (American National Standards Institute) si apoi de
catre ISO (International Organization for Standardization).

Softuri cunoscute de tip DBMS sunt:

- Microsoft SQL – produs Microsoft


- Oracle – produs Oracle Corporation
- DB2 – produs IBM

Desi fiecare dintre aceste pachete software implementeaza limbajul SQL, fiecare dintre ele
prezinta abateri de la standard sau extensii ale limbajului, care, pe de o parte duc la
performante mai bune sau o mai mare usurinta de utilizare, dar pe de alta parte introduc
incompatibilitati intre diversele softuri DBMS.

4
II. Structura informatiei dintr-un DBMS relational

O baza de date relationala este un ansamblu de informatie compus dintr-unul sau mai multe
tabele. Modalitatea fizica de stocare a datelor tine de softul DBMS folosit (diferind de la un
DBMS la altul). Gratie limbajului SQL, clientul poate manipula datele independent de aspectele
fizice ale stocarii datelor.

Informatiile sunt stocate in tabele. O baza de date poate contine zero sau mai multe tabele.

Tabele (relatii)

O tabela dintr-o baza de date relationala reprezinta un ansamblu de inregistrari cu structura


impusa, organizata tabelar (in randuri si coloane). Structura unei tabele este specificata la
crearea acesteia si presupune specificarea numarului de coloane si a numelui/tipului de
informatie al fiecareia dintre ele. Fiecare inregistrare (rand/record) din tabela va fi obligata apoi
sa aiba o valoare pentru fiecare dintre coloanele prezente in definitie.

Obs: Numarul de coloane este impus. Numarul de randuri este variabil.

Exemplu: Dorim sa cream o tabela in care sa stocam informatii despre facturi. Coloanele
necesare sunt: Id_Factura, Id_Client, Data_Factura, Valoare. Avem 4 coloane obligatorii si un
numar variabil de randuri. Vom impune pentru fiecare coloana tipul de date corespunzator.

Dupa crearea tabelei, se vor insera datele. Acestea respecta constrangerile de tip de data
impuse la crearea tabelei.

Coloane (atribute)

Fiecare coloana are un set de caracteristici:

- Numele (titlul) coloanei


- Tipul de date al coloanei. Toate valorile din coloana respctiva vor avea acelasi tip de
data
- Constrangeri (se vor discuta ulterior) – reguli aplicate asupra datelor din coloana
respectiva.

5
Desi in definitia unei tabele, coloanele sunt create intr-o anumita ordine, la extragerea datelor
din baza de date, ele pot fi reordonate.

Randuri (inregistrari)

Un rand al unei tabele reprezinta un ansamblu de valori (date), cate una corespunzatoare
fiecarei coloane. Fiecare valoare dintr-o tabela se afla la intersectia unei linii cu o coloana, o
valoare este unic identificata odata ce am specificat: serverul, baza de date, tabela, coloana
si randul.

Conceptul NULL

In implementarile de baze de date relationale exista conceptul de absenta a unei valori de pe o


coloana a unei inregistrari. Acest lucru contravine regulilor modelului relational original, care
impune ca toate inregistrarile sa aiba valori pentru toate coloanele. Pentru a indica absenta unei
valori pe o anumita linie/coloana, se plaseaza in acea coloana NULL. Din acest punct de
vedere, NULL nu poate fi considerat o valoare, si, precum se va vedea, nici nu se comporta ca
atare (in comparatii, operatii aritmetice).

Posibilitatea de a folosi NULL se stabileste la nivel de fiecare coloana, la crearea tabelei. In


aceeasi tabela putem avea coloane care permit NULL si coloane care il interzic (obligand astfel
toate inregistrarile sa aiba valoare pe acea coloana).

Transact SQL (T-SQL)

T-SQL este un dialect al standardului SQL. Toti furnizorii de baze de date, inclusiv Microsoft au
implementat dialect SQL ca principal limbaj in manipularea datelor in platformele lor de baze de
date. Pe de alta parte, nucleul limbajului este acelasi.

Utilizand standard SQL este best parctice. Codul este portabil si usor de implementat in alte
platforme.

Un exemplu cand alegem sa lucram in standard SQL folosim operatorul <> (diferit) fata de
operatorul nonstandard != (diferit).

6
III. SQL Data Types

SQL Server Management Studio (SSMS)

Management Studio este un software lansat pentru prima data cu versiunea Microsoft SQL
Server 2005, utilizat pentru configurarea, organizarea si administrarea componentelor Microsoft
SQL Server. Tool-ul include atat partea de interactiune grafica, cat si editare de scripturi in
vederea lucrului cu obiectele serverului.

Principala caracteristica a SSMS este Object Explorer:

Cu ajutorul Object Explorer se ierarhizeaza obiectele fiecarei instante SQL Server: Databases,
Security etc.

7
Baza de date Training (diagrama)

Baza de date captureaza toate vanzarile realizate intr-o companie, clientii companiei, precum si
tranzactiile dintre companie si furnizorii sai.

Baza de date contine urmatoarele informatii:

- Furnizorii care livreaza produsele companiei


- Clientii care cumpara de la companie
- Angajatii companiei
- Produsele existente in companie
- Transportatorii care transmit produsele de la comercianti la clientii finali
- Tranzactiile si detaliile despre acestea
- Facturile

8
Toate aceste informatii sunt stocate in diferite tabele. Tabelele au denumiri, in functie de ce
informatii detin. Scopul crearii mai multor tabele este de a da userului o imagine de ansamblu
asupra procesului de business si ce rapoarte sunt necesare si pot fi extrase. Relatiile dintre
tabele ne redau flow-ul de business.

Tabelele sunt organizate pe diferite scheme: dbo, HR, Production, Sales, Stats.

Schema – reprezinta un container sau un mod de organizare a tabelelor in functie de diferite


procese de business. Dbo schema este schema default. Totodata, organizarea tabelelor pe
scheme, reprezinta si un aspect de securitate (exemplu: anagajatii companiei nu vor avea
acces pe schema HR, decat cei din respectivul departament).

Tabele

Tabelele sunt obiectele in care stocam informatiile. Au un numar definit de coloane si un numar
variabil de randuri. Fiecare coloana are un nume, tip de date si constrangeri, daca este cazul.

Tipuri de date

Principalele tipuri de date sunt:

Exact numeric:

- Bigint
- Int
- Smallint
- Tinyint

9
Data type Range Storage

bigint -2^63 (-9,223,372,036,854,775,808) to 2^63-1 (9,223,372,036,854,775,807) 8 Bytes

int -2^31 (-2,147,483,648) to 2^31-1 (2,147,483,647) 4 Bytes

smallint -2^15 (-32,768) to 2^15-1 (32,767) 2 Bytes

tinyint 0 to 255 1 Byte

- Bit – poate lua valorile 0 (false), 1 (true), NULL


- Decimal

decimal[ (p[ , s] )] , unde p (precision) si s (scale)

p – reprezinta numarul total de digits stocati, la stanga si la dreapta de punctul zecimal. Prezicia
trebuie sa fie un numar intre 1 (minim) si 38 (maxim). Precizia default este 18.

s – reprezinta numarul de digits stocati la dreapta punctului zecimal. Scala poate fi un numar
intre 0 si p. Scala default este 0.

Precision Storage bytes

1-9 5

10-19 9

20-28 13

29-38 17

- Money

Data type Range Storage

money -922,337,203,685,477.5808 to 922,337,203,685,477.5807 8 bytes

10
smallmoney - 214,748.3648 to 214,748.3647 4 bytes

Date and Time:

- Date (yyyy-mm-dd)

Range 0001-01-01 through 9999-12-31


January 1, 1 A.D. through December 31, 9999 A.D.

Storage size 3 bytes, fixed

Calendar Gregorian

- Datetime

Date range January 1, 1753, through December 31, 9999

Time range 00:00:00 through 23:59:59.997

Storage size 8 bytes

Calendar Gregorian (Does not include the complete range of years.)

- Smalldatetime

Date range 1900-01-01 through 2079-06-06


January 1, 1900, through June 6, 2079

Time range 00:00:00 through 23:59:59


2007-05-09 23:59:59 will round to
2007-05-10 00:00:00

Storage size 4 bytes, fixed.

Calendar Gregorian
(Does not include the complete range of years.)

11
Character string:

- Char(n) – lungime fixa egala cu n (numarul de caractere permise). n poate lua valori
intre 1 si 8000. Dimensiunea este egala cu n bytes.
- Varchar(n) – lungime variabila egala cu n. Dimensiunea este egala cu n bytes plus 2
bytes.
- Varchar(max) – max indica maximul dimensiunii egal cu 2^31-1 byte (2GB).

Obs: Cand n nu este specificat, lungimea default este 1.

- Nchar(n) – n poate lua o valoare intre 1 si 4000 (2 character set). Dimensiunea este de
doua ori n bytes. Este dimensiune fixa.
- Nvarchar(n) - n poate lua o valoare intre 1 si 4000 (2 character set). Dimensiunea este
de doua ori n bytes. Este dimensiune variabila.
- Nvarchar(max) - max indica maximul dimensiunii egal cu 2^31-1 byte (2GB).

12
IV. Setul de comenzi T-SQL: SELECT si FROM

Baza de date Training (diagrama)

Evaluarea logica a unei interogari (query)

Sintaxa unei interogari SQL este urmatoarea, precum si ordinea de scriere a clauzelor:

1. SELECT <<coloane>>
2. FROM <<tabele>>
3. WHERE <<conditii>>
4. GROUP BY <<agregari>>
5. HAVING <<conditii pe agregari>>

13
6. ORDER BY <<ordonarea datelor>>

Evaluarea logica a interogarii se realizeaza astfel:

1. FROM <<tabele>>
2. WHERE <<conditii>>
3. GROUP BY <<agregari>>
4. HAVING <<conditii pe agregari>>
5. SELECT <<coloane>>
6. ORDER BY <<ordonarea datelor>>

Exemplu:

SELECT Extragem
country Tara
, YEAR(hiredate) AS yearhired Anul angajarii
, COUNT(*) AS numemployees Numarul total de anagajati
FROM HR.Employees Din tabela Employees, schema HR

WHERE hiredate >= '20030101' Cu conditia ca data angajarii sa fie cel putin 1
ianuarie 2003
GROUP BY country Grupam datele dupa tara
, YEAR(hiredate) si anul angajarii pentru ca avem o functie de
agregare (COUNT)
HAVING COUNT(*) > 1 Consideram doar tarile si anii de angajare cu
mai mult de 1 angajat
ORDER BY country Ordonam datele dupa tara
, yearhired DESC; si anul angajarii

Rezultat:

14
Obs: Deoarece ORDER BY este evaluat dupa SELECT, atunci aliasul pentru extragerea anului
(yearhired) este recunoscut, ceea ce inseamna ca putem ordona dupa alias (redenumire
coloanei)

Evaluarea logica a interogarii:

- Prima clauza evaluata este clauza FROM. In clauza FROM este (sunt) indicat(e) tabelul
(tabelele). Daca se extrag date din mai multe tabele, atunci apare si notiunea de JOIN si
fiecare tabel va primi un alias (un nume). JOIN-urile se vor discuta ulterior.

select * FROM HR.Employees afiseaza toate datele din tabela HR.Employees (9 randuri)

- Cea dea doua clauza evaluata este clauza WHERE, clauza care ne permite sa filtram
randurile din tabel(e). Randurile care sunt evaluate la False sau la Unknown nu sunt
afisate.

select *
FROM HR.Employees
WHERE hiredate >= '20030101'
(7 randuri)

Obs: Clauza WHERE nu recunoaste alias-urile pentru ca este evaluata inaintea clauzei
SELECT. In cadrul clauzei SELECT se stabilesc alias-urile pentru coloane.

SELECT country, YEAR(hiredate) AS yearhired FROM HR.Employees WHERE yearhired >= 2003
Msg 207, Level 16, State 1, Line 2
Invalid column name 'yearhired'.

- A treia clauza evaluata este clauza GROUP BY. Clauza GROUP BY permite gruparea
randurilor in functie de coloanele specificate (country si year(hiredate)).

15
SELECT country
, YEAR(hiredate) AS yearhired
, count(*) Nr_Angajati
FROM HR.Employees
WHERE hiredate >= '20030101'
GROUP BY country
, YEAR(hiredate)

- Cea de-a patra clauza evaluata este clauza HAVING. Clauza ne permite sa extragem
doar gruparile cu mai mult de un angajat. Sunt afisate doar randurile unde conditia este
True (nu sunt afisate randurile unde conditia este evaluata la False sau Unknown).

SELECT country
, YEAR(hiredate) AS yearhired
, count(*) Nr_Angajati
FROM HR.Employees
WHERE hiredate >= '20030101'
GROUP BY country
, YEAR(hiredate)
HAVING COUNT(*) > 1

- Cea de-a cincea clauza evaluata este clauza SELECT. In cadrul clauzei, mai intai se
evalueaza expresiile si atribuie alias-uri coloanelor rezultate. Dupa evaluarea expresiilor,
se evalueaza clauza DISTINCT, daca aceasta este specificata. DISTINCT extrage
inregistrarile unice.
- Clauza ORDER BY este ultima evaluata, implicit dupa clauza SELECT, ceea ce
inseamna ca in cadrul lui ORDER BY putem utiliza alias-uri sau numarul de coloane.

SELECT country
, YEAR(hiredate) AS yearhired
, count(*) Nr_Angajati
FROM HR.Employees
WHERE hiredate >= '20030101'
GROUP BY country
, YEAR(hiredate)
HAVING COUNT(*) > 1

16
ORDER BY 1 , 2 DESC;

Utilizarea clauzelor FROM si SELECT

Clauza FROM

Clauza FROM este prima clauza evaluata din cadrul unei interogari.

Clauza FROM are doua roluri importante:

- Este clauza unde sunt indicate tabele din care se extrag informatiile
- Este clauza unde sunt aplicatii operatorii de tip JOIN.

Exemplu:

SELECT empid, firstname, lastname FROM HR.Employees;

Unde:

- HR – schema
- Employees – tabela

Obs: In anumite cazuri, schema poate fi omisa, insa se va considera schema default: dbo

Exemplu:

SELECT * FROM Nums;

In cadrul clauzei FROM se pot specifica si alias-uri pentru tabele. Alias-ul este un nume scurt
asociat tabelei, de obicei litera cu care incepe tabelul.

Obs: Daca un tabel primeste alias, atunci numele intreg al tabelului nu mai este recunoscut.

Exemplu (codul nu ruleaza):

SELECT e.empid, e.firstname, Employees.lastname FROM HR.Employees AS E

17
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "Employees.lastname" could not be bound.

Exemplu (codul ruleaza si avem alias e):

SELECT e.empid, e.firstname, e.lastname FROM HR.Employees AS E

Exemplu (codul ruleaza si nu avem alias):

SELECT Employees.empid, Employees.firstname, Employees.lastname FROM HR.Employees

Clauza SELECT

Clauza SELECT este ultima clauza evaluata. Are doua roluri principale:

- Evalueaza expresiile care definesc atributele (coloanele) din rezultatul interogarii,


asigneaza alias-uri coloanelor daca e necesar
- Utilizand clauza DISTINCT se vor elimina randurile duplicate din rezultatul interogarii

Exemple:

SELECT empid, firstname FROM HR.Employees;


- Returneaza cele doua coloane din tabela HR.Employees

18
SELECT * FROM HR.Employees;
- Asterix (*) returneaza toate coloanele din tabela HR.Employees.

Obs: Returnarea tuturor coloanelor nu este best practice. Trimitand mai multe date decat este
nevoie, poate avea un impact negativ asupra performantei sistemului.

Clauza SELECT permite atribuirea alias-urilor coloanelor.

Exemplu:

SELECT empid AS employeeid, firstname, lastname FROM HR.Employees;


- Emplyeeid este un alias pentru empid

Obs: Daca se omite virgula dintre firstname si lastname, atunci lastname devine alias pentru
coloana firstname.

Exemplu:

SELECT empid AS employeeid, firstname lastname FROM HR.Employees;

19
Exemplu: Sa se determine empid, si Numele (lastname concatenat cu firstname) angajatilor.

Operatorul de concatenare este „+”.

SELECT empid AS employeeid, lastname+firstname as Nume FROM HR.Employees;

- Rezultatul interogarii contine numele si prenumele unite.

Vom concatena lastname cu spatiu si cu firstname.

SELECT empid AS employeeid, lastname+' '+firstname as Nume FROM HR.Employees;

Clauza DISTINCT este utilizata pentru a elimina randurile duplicate din rezultatul unei
interogari.

Exemplu: Sa se determine tara, regiunea si orasul angajatilor.

20
- Fara clauza DISTINCT

SELECT country, region, city FROM HR.Employees;

- Clauza DISTINCT

SELECT DISTINCT country, region, city FROM HR.Employees;

Una dintre diferentele dintre standard SQL si T-SQL este faptul ca in standard SQL nu poate
exista doar clauza SELECT fara clauza FROM, pe cand in T-SQL poate fi de sine statatoare
clauza SELECT.

Exemplu:

select 10 as Nr_Angajati, getdate() as "Data Curenta", 'ABC Company' [Nume Companie]

Obs: Functia getdate() returneaza data si ora curente. ABC Company este intre apostrofuri
pentru ca este un text.

Delimitatori de identificare

Identificarea atributelor, schemelor, tabelelor sau a altor obiecte poate fi facuta cu ajutorul
delimitatorilor.

21
Delimitatori: T-SQL utilizeaza duble ghilimele (” ”) pentru identificarea obiectelor, precum si
paranteza dreapta dubla ([ ]).

Utilizarea acestora este optionala atunci cand identificatorii sunt regulari: tabela Orders, schema
Sales, coloana OrderDate. Regula pentru identifcatorii regulari este: primul caracter trebuie sa
fie o litera de la A la Z (mica sau mare). Nu pot fi utilizate cuvinte cheie din T-SQL, nu pot exista
spatii si nici caractere speciale.

Daca identificatorii nu urmeaza regula de mai sus, atunci delimitatorii devin obligatorii si
identificatorii se numeste iregulari: coloana [Order Data], tabela ”Orders 2016”.

22
Exercitii:

1. Sa se determine toti clientii companiei si toate informatiile despre acestia (tabela


Customers).
2. Sa se determine id-ul de client (custid), numele clientului (companyname), persoana de
contact (contactname) pentru fiecare client (tabela Customers).
3. Sa se determine orasul (city) si tara (country) pentru fiecare client. Sa se extraga datele
neduplicate (tabela Customers).
4. Sa se modifice interogarea anterioara astfel incat coloana city va avea alias-ul Oras,
coloana country va avea aliasul Tara, tabela Customers va avea aliasul Cu. Sa se
utilizeze aliasul Cu in prefixarea coloanelor.
5. Sa se modifice interogarea anterioara astfel incat sa se adauge 2 coloane in rezultatul
interogarii: coloana Data Interogarii care va contine valoarea functiei getdate(), coloana
Numele Companiei care va contine textul Trade Company.
6. Sa se determine data curenta intr-o interogare separata.
7. Sa se determine numele clientului si numele persoanei de contact intr-o singura coloana
(se vor concatena informatiile utilizand separatorul „-„).
8. Sa se ruleze toate interogariile de mai sus intr-o singura fereastra.
9. Determinati daca interogarea de mai jos este corecta:
SELECT Customers.Custid,
Customers.companyname
FROM [Training].[Sales].[Customers] Cu

10. Determinati daca interogarea de mai jos este corecta:


SELECT Custid,
companyname
contactname
FROM [Training].[Sales].[Customers]

23
V. Setul de comenzi T-SQL: Filtrare si Sortare Date

Clauza WHERE este cea de-a doua clauza evaluata, dupa clauza FROM.

Exemplu: Sa se determine toti angajatii cu regiunea WA.

SELECT empid, firstname, lastname, country, region, city FROM HR.Employees WHERE region
='WA';

Rezultatul interogarii sunt cele 5 randuri de mai sus.

Exemplu: Sa se determine toti angajatii cu regiunea diferita de WA.

SELECT empid, firstname, lastname, country, region, city FROM HR.Employees WHERE region
<>'WA';

Rezultatul interogarii – 0 randuri.

Obs: Daca selectam toti angajatii din tabela Employees fara sa filtram dupa regiune:

SELECT empid, firstname, lastname, country, region, city FROM HR.Employees

observam ca in coloana region aveam NULL si WA, iar cand interogarea a fost sa selectam toti
angajatii cu regiunea diferita de WA, rezultatul nu a fost cele 4 randuri cu NULL, ci 0 randuri.

24
NULL reprezinta „missing value”, nu o valoare NULL. Cand regiunea este NULL, operatorul
<> WA evalueaza predicatul la „unknown”, adica nu se cunoaste regiunea (nu a fost completata
in baza de date).

Pentru a returna toti angajatii care au regiunea diferita de WA, interogarea va fi construita astfel:

SELECT empid
, firstname
, lastname
, country
, region
, city
FROM HR.Employees
WHERE region <> 'WA'
OR region IS NULL;

Obs: Filtrarea datelor este un lucru foarte important pentru performanta interogarii. Filtrand
datele, inseamna ca tabela nu este scanata in intregime si astfel se reduce traficul in retea. O
alta metoda pentru a imbunatatii performanta unei interogarii este prin utilizarea indecsilor (se
va discuta mai tarziu).

Utlizarea operatorilor logici: AND, OR, NOT

Exemplu: Sa se determine toti clientii din UK sau USA.

SELECT custid
, companyname
, country
FROM [Training].[Sales].[Customers]
WHERE country='UK' or country='usa'

Rezultatul interogarii – 20 de randuri.

Exemplu: Sa se determine toti clientii din UK sau USA cu functia de Sales Representative.

SELECT custid

25
, companyname
, contacttitle
, country
FROM [Training].[Sales].[Customers]
WHERE (country='UK' or country='usa') and contacttitle='Sales Representative'

Obs: Intrucat clientii sunt fie din UK, fie din USA, dar indiferent de tara, au functia de Sales
Representative, atunci vom utiliza in filtrarea datelor si operatorul AND, pe langa operatorul OR.

Scrierea filtrelor se va face utilizand paranteze, pentru a reuni multimea clientilor din UK cu
multimea clientilor din USA, rezultand astfel o singura multime de clienti, asupra careia aplicam
urmatorul filtru, cel cu functia de Sales Representative, astfel restragem multimea rezultata.

Exemplu: Sa se determine toti clientii din UK cu functia de Sales Representative si clientii din
Canada cu functia de Accounting Manager.

SELECT custid
, companyname
, contacttitle
, country
FROM [Training].[Sales].[Customers]
WHERE (country='UK' and contacttitle='Sales Representative') or
(country='Canada' and contacttitle='Accounting Manager')

Exemplu: Sa se determine toti clientii care nu sunt din Spania, dar au functia fie de Marketing
Manager, fie de Sales Associate.

SELECT [custid]
,[companyname]
,[contacttitle]
,[country]
FROM [Training].[Sales].[Customers]
where country <> 'Spain'
and contacttitle in ('Marketing Manager','Sales Associate')
Rezultatul interogarii – 18 randuri.

Filtrarea informatiilor de tip Date and Time

Exemplu: Sa se determine toate tranzactiile (tabela Sales.Orders) din 2008.

26
SELECT [orderid]
,[custid]
,[empid]
,[orderdate]
FROM [Training].[Sales].[Orders]
where [orderdate]>='2008-01-01' and [orderdate]<='2008-12-31'
sau

SELECT [orderid]
,[custid]
,[empid]
,[orderdate]
FROM [Training].[Sales].[Orders]
where [orderdate] between '2008-01-01' and '2008-12-31'
Rezultatul interogarii – 270 de randuri

Exemplu: Sa se determine toate tranzactiile din 2006 de valoare cuprinsa intre 50 si 100.

SELECT [orderid]
,[custid]
,[empid]
,[orderdate]
,freight
FROM [Training].[Sales].[Orders]
where ([orderdate] between '2006-01-01' and '2006-12-31')
and freight between 50 and 100
Rezultatul interogarii – 32 de randuri

Obs: Scrierea filtrelor de tip date and time se va face in limbaj neutru. De exemplu, '20070212'

Intotdeauna este interpretat ymd. De asemenea, '2007-02-12' este scriere in limbaj neutru doar
daca coloana filtrata este tip: DATE, SMALLDATETIME, DATETIME, DATETIME2,
DATETIMEOFFSET.

Utilizarea operatorului LIKE

Sintaxa operatorului LIKE este: column LIKE pattern

Exemplu: Sa se determine toti angajatii al caror lastname incepe cu D.

SELECT empid, firstname, lastname FROM HR.Employees WHERE lastname LIKE 'D%';

Exemplu: Sa se determine toti angajatii al caror firstname se termina cu A.

27
SELECT empid, firstname, lastname FROM HR.Employees WHERE firstname LIKE '%A';

Exemplu: Sa se determine toti angajatii al caror firstname contine AR.

SELECT empid, firstname, lastname FROM HR.Employees WHERE firstname LIKE '%AR%';

Obs: In utilizarea operatorului LIKE, exceptand %, se poate utiliza si underscore (_).


Underscore marcheaza un singur caracter.

Exemplu: Sa se determine toti clientii a caror regiune incepe cu W si numele regiunii are 2
caractere.

SELECT
custid
,companyname
,region
from [Sales].[Customers] where region like 'W_'

Clauza ORDER BY este ultima clauza evaluata, deci dupa clauza SELECT. Clauza ORDER BY
sorteaza datele ascendent (ASC) sau descendent (DESC).

Obs: Nespecificarea clauzei ORDER BY intr-o interogarea nu garanteaza ca rezultatul


interogarii este sortat intr-o anumita ordine. Singura metoda prin care garantam ordonarea
rezultatului unei interogari este utilizarea clauzei ORDER BY.

Exemplu: Sa se determine toti angajatii din regiunea WA ordonati ascendent dupa oras.

SELECT empid , firstname , lastname , city


FROM HR.Employees
WHERE region = 'WA'

28
ORDER BY city;

Obs: Daca nu se specifica tipul de sortare (ASC sau DESC), atunci sortarea implicita va fi
ascendenta.

Exemplu: Sa se determine toti angajatii din regiunea WA ordonati descendent dupa oras.

SELECT empid , firstname , lastname , city


FROM HR.Employees
WHERE region = 'WA'
ORDER BY city DESC;

Obs: Observam ca avem doi angajati din acelasi oras. Cei doi angajati nu sunt sortati intr-o
anumite ordine.

Exemplu: Sa se determine toti angajatii din regiunea WA ordonati descendent dupa oras si id-ul
de angajat.

SELECT empid , firstname , lastname , city


FROM HR.Employees
WHERE region = 'WA'
ORDER BY city DESC, empid DESC;

Obs: Tinand cont ca ORDER BY este evaluata dupa clauza SELECT, putem specifica in cadrul
interogarii numarul de coloana (coloane) dupa care se doreste sortarea.

SELECT empid , firstname , lastname , city


FROM HR.Employees
WHERE region = 'WA'
ORDER BY 4 DESC, 1 DESC;

29
Rezultatul este acelasi cu rezultatul interogarii anterioare.

Obs: De asemenea, din aceleasi considerente de evaluare a clauzei ORDER BY, putem sorta
datele si dupa alias-uri.

Exemplu: Sa se determine toti angajatii si anul nasterii lor, angajati din regiunea WA; angajatii
sa fie ordonati descendent dupa anul nasterii.

SELECT empid , firstname , lastname , city , year(birthdate) Birth_Year


FROM HR.Employees
WHERE region = 'WA'
ORDER BY Birth_Year DESC

Obs: Pot fi sortate datele si in functie de coloane care nu sunt afisate in SELECT, dar sunt
prezente in tabele.

Exemplu: Sa se determine toti angajatii din regiunea WA. Angajatii vor fi sortati ascendent dupa
data nasterii.

SELECT empid , firstname , lastname , city


FROM HR.Employees
WHERE region = 'WA'
ORDER BY birthdate

Obs: Daca sortarea datelor se va face in functie de coloana ce contine NULL, atunci NULL-urile
vor fi afisate primele si apoi valorile non-null.

Exemplu: Sa se determine toate tranzactiile clientului cu id-ul 20 si sa se ordoneze datele


ascendent dupa data de expeditie a comenzii.

SELECT orderid, shippeddate

30
FROM Sales.Orders
WHERE custid = 20
ORDER BY shippeddate

Filtrare date utilizand optiunea TOP

- Numar de randuri

Cu ajutorul optiunii TOP putem filtra un numar specificat de randuri. Optiunea TOP se
mentioneaza imediat dupa clauza SELECT.

Exemplu: Sa se determine cele mai recente 3 tranzactii din tabela Orders in functie de data
tranzactiei.

SELECT TOP 3 orderid, orderdate, custid, empid


FROM Sales.Orders
ORDER BY orderdate DESC;

Obs: Optiunea TOP se utilizeaza impreuna cu clauza ORDER BY. In caz contrar se extrag 3
randuri aleatorii din tabela mentionata.

- Procent

In mod similar se pot extrage primele 10% tranzactii in functie de valoarea tranzactiei.

select top (10) percent orderid, orderdate, freight


from Sales.Orders
order by freight desc

Rezultatul interogarii – 83 de randuri (in total, in tabela Orders sunt 830 randuri).

31
- With Ties

In cazul in care ultimul rand rezultat are valoarea coloanei mentionata in clauza ORDER BY
egala cu a altor randuri, pentru a returna si celelalte randuri, se utilizeaza optiunea WITH TIES.

Exemplu: Sa se determine cele mai recente 3 tranzactii din tabela Orders in functie de data
tranzactiei. Daca ultimul ultima tranzactie are aceeasi data cu a altor tranzactii, sa se returneze
toate tranzactiile.

SELECT TOP 3 with ties orderid, orderdate, custid, empid


FROM Sales.Orders
ORDER BY orderdate DESC;

Exercitii:

1. Sa se ruleze scriptul 02. Create db Bank.sql (scriptul creeaza o baza de date cu mai
multe tabele relationate)

32
2. Sa se extraga urmatoarele informatii din baza de date Bank.
- Sa se determine lista de tranzactii care au valoarea peste 300. Sa se ordoneze
tranzactiile descendent dupa data tranzactiei.
- Sa se extraga top 7 tranzactii cele mai recente.
- Sa se modifice interogarea anterioara astfel incat, daca ultima tranzactiei are aceesi
datatranzactie cu alte tranzactii, acestea din urma sa fie afisate.
- Sa se determine lista de tranzactii care sunt efectuate pe conturile 999991 si 999995.
- Sa se determine lista de tranzactii care au valoarea intre 100 si 1000 si sunt efectuate in
2009.
- Sa se determine lista de tranzactii care sunt de tip Plata Salariu (se preia id-ul tipului de
tranzactie din tabela tiptranzactii).
- Sa se determine lista de tranzactii efectuate de Client 1 (se preia id-ul clientului din
tabela clienti, pentru acest id de client, identificam conturile lui si pentru conturile
identificate extragem tranzactiile). Sa se ordoneze datele crescator dupa nr de cont,
descrescator dupa valoarea tranzactiei.

33
VI. Setul de comenzi T-SQL: Grupare si Agregare date

Clauza GROUP BY

Clauza GROUP BY permite gruparea datelor in mai multe seturi de date, iar, ulterior aceste
seturi date pot fi prelucrate utilizand: functii de agregare si filtrari.

Datele se grupeaza utilizand seturi de atribute, acestea numindu-se grouping set.

Functii de agregare

- COUNT (coloana) – numara cate valori not null exista in coloana mentionata
- COUNT (*) – numara toate randurile
- COUNT(distinct coloana) – numara cate valori distincte exista in coloana mentionata
- SUM(coloana) – insumeaza valorile din coloana mentionata
- MAX(coloana) – determina valoarea maxima din coloana mentionata
- MIN(coloana) – determina valoarea minima din coloana mentionata
- AVG(coloana) – determina media aritmetica a valorilor nenule din coloana mentionata

Exemplu:

SELECT
count([shipregion]) Nr_Valori_NOTNULL
,count(*) Nr_randuri
,count(distinct [shipregion]) Nr_Valori_Distinct
FROM [Training].[Sales].[Orders]

Obs: Datorita faptului ca nu a fost specificat un set de atribute de grupare, interogarea de mai
sus returneaza un singur set de date.

Exemplu: Sa se determine pentru fiecare shipregion, numarul de tranzactii.

SELECT [shipregion]
,count(*) Nr_Tranzactii
FROM [Training].[Sales].[Orders]
group by [shipregion]
order by [shipregion]

34
Rezultatul interogarii – 20 randuri

Obs:

Setul de atribute de grupare este format dintr-un singur atribut: shipregion. Este utilizata functia
de agregare COUNT(*).

Daca nu se specifica functia de agreare, rezultatul interogarii este tot 20 rows, insa nu va mai fi
afisat numarul de randuri pentru fiecare regiune.

SELECT [shipregion]
--,count(*) Nr_Tranzactii
FROM [Training].[Sales].[Orders]
group by [shipregion]
order by [shipregion]

Exemplu: Sa se determine la nivel de shipregion si anul tranzactiei, numarul total de tranzactii.

SELECT [shipregion]
,year(orderdate) An_tranzactie
,count(*) Nr_Tranzactii
FROM [Training].[Sales].[Orders]
group by [shipregion]
,year(orderdate)
order by [shipregion]

Rezultatul interogarii – 55 randuri

35
Exemplu: Sa se determine la nivel de shipregion si shipcity: numarul total de tranzactii, suma
valorilor, media aritmetica valorilor, cea mai mare valoare, cea mai mica valoare – freight.

select
shipregion
,shipcity
,count(*) Nr_Tranzactii
,sum(freight) Total_Val
,avg(freight) Media_Arit
,max(freight) Max_Val
,min(freight) Min_Val
from [Training].[Sales].[Orders]
group by
shipregion
,shipcity

Rezultatul interogarii – 70 randuri.

Exemplu: Sa se determine la nivel de shipcity si anul tranzactiei, suma valorilor si media


aritmetica, doar pentru tranzactiile cu valoarea de cel putin 50. Sa se ordoneze datele
ascendent dupa anul tranzactiei.

select
shipcity
,year(orderdate) An_Tranzactie
,count(*) Nr_Tranzactii
,sum(freight) Total_Val
,avg(freight) Media_Arit
from [Training].[Sales].[Orders]
where freight>=50
group by
shipcity
,year(orderdate)
order by 2

Rezultatul interogarii – 133 randuri.

36
Obs: year(orderdate) extrage anul din data tranzactiei (orderdate). Conditia de freight>=50
extrage doar randurile din tabel unde freight este de cel putin 50. Setul de atribute de grupare
este format din shipcity si se regaseste atat in clauza select, cat si in clauza group by. Order by
2 (este specificat numarul coloanei) este posibil deoarece clauza order by se evalueaza dupa
clauza select, deci se cunosc coloanele extrase.

Clauza HAVING

Clauza HAVING se utilizeaza atunci cand se filtreaza seturi de date. In cadrul clauzei having,
conditiile sunt la nivel de functii de agregare. Clauza WHERE este la nivel de randuri dintr-o
tabela, pe cand clauza HAVING este la nivel de set de date.

Exemplu: Sa se determine suma valorilor tranzactiilor la nivel de shipcity, considerandu-se doar


orasele cu o valoare totala intre 3000 si 5000.

select
shipcity
,year(orderdate)
,sum(freight) Total_Val
from [Training].[Sales].[Orders]
group by
shipcity
,year(orderdate)
having sum(freight) between 3000 and 5000
order by 2

Exemplu: Sa se determine suma valorilor tranzactiilor la nivel de shipcity, considerandu-se doar


orasele cu o valoare totala intre 3000 si 5000 si tranzactiile cu o valoare de cel mult 1000.

select
shipcity
,year(orderdate)
,sum(freight) Total_Val
from [Training].[Sales].[Orders]
where freight<=1000
group by
shipcity
,year(orderdate)
having sum(freight) between 3000 and 5000
order by 2

37
Exercitii:

Se va utiliza baza de date Bank.

1. Sa se determine la nivel de an tranzactie, suma incasarilor, doar pentru tranzactiile de


cel putin 500.
2. Sa se determine la nivel de an tranzactie si luna, suma incasarilor. Sa se afiseze doar
lunile unde totalul depaseste 800.
3. Sa se determine la nivel de fiecare cont si tip tranzactie media valorilor tranzactiilor, cea
mai mare incasare si numarul de tranzactii. Nu vor fi afisate tranzactiile de tip 2. Sa se
ordoneze datele descendent dupa tip tranzactie si cont.
4. Sa se determine la nivel de fiecare cont suma valorilor. Vor fi afisate doar conturile cu o
valoare totala de cel putin 200. Se vor exclude tranzactiile de tip 1 si 2.

38
VII. Utilizare JOIN. Tipuri de JOIN

Adesea, datele necesare in rapoarte fac parte din mai multe tabele. Un mediu de baze date cu
cat este mai mult normalizat (se va discuta ulterior), cu atat mai multe tabele avem. Tabelele
sunt relationate intre ele prin chei: in tabela principala avem PRIMARY KEY, in tabela de
legatura avem FOREIGN KEY.

PRIMARY KEY

Cheia primara a unei tabele reprezinta ansamblul minim de campuri (sau doar un singur camp)
care identifica in mod unic o inregistrare dintr-o tabela. Pe o tabela poate exista cel mult o cheie
primara.
Campul/ ansamblul de campuri pe care se defineste cheia primara nu admite NULL si trebuie
sa contina date unice (exemplu: numarul de factura, codul de client, codul de produs).

T-SQL suporta 3 tipuri de joinuri: cross, inner si outer pentru a extrage informatii din mai multe
tabele.
INNER JOIN
Inner join returneaza partea comuna din doua tabele. Legatura dintre cele doua tabele se
realizeaza prin campul/campurile comun/comune.
Exemplu: Sa se determine toate produsele din categoria Seafood cu pretul de cel putin 15.
select
*
from [Production].[Categories] c
inner join Production.Products p on c.categoryid=p.categoryid
where c.categoryname='Seafood' and p.unitprice>=15

- Legatura dintre cele doua tabele este categoryid

39
- Cele doua tabele au alias-uri: Categories alias c, products alias p. Motivul adaugarii
alias-urilor este utilizarea coloanei comune categoryid, pentru a stii din ce tabela se
preia coloana categoryid.

OUTER JOINs
LEFT OUTER JOIN (LEFT JOIN) – returneaza toate randurile din tabela din stanga si doar
randurile din tabela din dreapta care se regasesc si in prima tabela.
Exemplu: Sa se determine toti clientii si facturile acestora. Anumiti clienti nu au inca facturi.

select
c.custid
, c.companyname
, o.orderid
, o.orderdate
from Training.sales.Customers c
left join Training.[Sales].[Orders] o on o.custid=c.custid

Rezultatul interogarii – 832 randuri. 2 clienti nu au facturi.

Exemplu: Sa se determine toti clientii care inca nu au facturat.


select
c.custid
, c.companyname
, o.orderid
, o.orderdate
from Training.sales.Customers c
left join Training.[Sales].[Orders] o on o.custid=c.custid
where o.orderid is null

40
Exercitii:
1. Sa se determine clientii unici care au conturi cu balanta intre 1000 si 50000.
2. Sa se modifice interogarea anterioara astfel incat sa se afiseze si cate conturi sunt.
3. Sa se afiseze clientii si conturile de tip depozit (sunt doua inner join-uri)
4. Sa se determine clientii, conturile si tranzactiile de tip Plata Salariu.
5. Sa se determine toate conturile pe care nu exista tranzactii efectuate.
6. Sa se determine toate tipurile de tranzactii pentru care nu exista tranzactii.
7. Sa se determine la nivel de tip cont si tip tranzactie: cate tranzactii sunt, cati clienti distincti
au efectuate tranzactiile, cate conturi distincte exista pentru aceste tranzactii.

41
VIII. Setul de comenzi T-SQL: CASE, COALESCE, ISNULL

Expresia CASE – returneaza o valoarea. Evalueaza un set de conditii logice si in urma


evaluarii afiseaza rezultatul.

Expresia CASE are rolul de testa anumite conditii si de a afisa valoarea/coloana conditiei
adevarate.

CASE – forma de cautare: in afara faptului ca utilizeaza o expresie de intrare, evaluarea in


functie de expresia WHEN poate fi facuta cu expresii mai complexe.

Exemplu: Sa se verifice daca preturile produselor se incadreaza in urmatoarele intervale: intre 0


si 30, intre 30 si 60 si peste 60.

select
productid
,productname
,case
when unitprice<=30 then 'intre 0 si 30'
when unitprice<=60 then 'intre 31 si 60'
else 'peste 61' end as Interval_Pret
from Training.Production.Products

Evaluarea expresiei WHEN, indiferent de forma, se va face in ordinea conditiilor.

Functia COALESCE – este o abreviere a expresiei CASE. Coalesce este o functie standard,
nu asociata T-SQL.

Functia COALESCE accepta o lista de expresii de intrare si returneaza prima expresie nenull
sau NULL, daca toate expresiile sunt NULL.

42
Exemplu: Sa se afiseze fax-ul pentru fiecare client. In cazul in care fax-ul nu este completat
(NULL), atunci sa se afiseze numarul de telefon.

select
custid
,companyname
,fax
,phone
,coalesce(fax,phone) as Contact
from Training.Sales.Customers

Rezultatul interogarii – 91 de randuri

Functia ISNULL – este o abreviere a expresiei CASE. Functia ISNULL este nonstandard.
Functia ISNULL are doua argumente: expresia considerata pentru verificare daca este NULL si
expresia care va fi returnata in cazul in care prima expresie este NULL.

Exemplu: Sa se afiseze textul „nu are fax” pentru clientii care nu au faxul completat.
select
custid
,companyname
,fax
,phone
,isnull(fax,'nu are fax') as Contact
from Training.Sales.Customers

Rezultatul interogarii – 91 de randuri.

43
Obs: Rezultatul functiei COALESCE va avea data type-ul expresiei rezultat. Rezultatul functiei
ISNULL va avea data type-ul primei expresii.

DECLARE @x AS VARCHAR(3) = NULL


DECLARE @y AS VARCHAR(10) = '1234567890';

SELECT COALESCE(@x, @y) AS [COALESCE]


, ISNULL(@x, @y) AS [ISNULL]

44
IX. Functii de data si ora: YEAR, MONTH, DAY, DATEDIFF, DATEADD

Functiile YEAR, MONTH, DAY

Functia YEAR extrage anul dintr-o data calendaristica.

Functia MONTH extrage luna dintr-o data calendaristica.

Functia DAY extrage ziua dintr-o data calendaristica.

Exemplu: Sa se determine numarul de angajati din companie grupati pe fiecare an al angajarii.

select
year(hiredate) Anul_Anagajarii
,count(*) Nr_Angajati
from Training.hr.Employees
group by year(hiredate)

Exemplu: Sa se determine pentru fiecare comanda: anul, luna si ziua. Sa se filtreze infromatiile
doar pentru anul 2006. Sa se ordoneze datele ascendent dupa luna, ascendent dupa zi.

select
orderid
,year(orderdate) An_Comanda
,month(orderdate) Luna_Comanda
,day(orderdate) Zi_Comanda
from Training.Sales.Orders
where year(orderdate)=2006
order by month(orderdate), day(orderdate)

Rezultatul interogarii – 152 de randuri.

Functia DATEDIFF returneaza diferenta dintre doua date calendaristice. Unitatea de masura
pentru diferenta este data ca input de catre utilizator.

45
Sintaxa functiei DATEDIFF:

Datediff(datepart, startdate, enddate), unde:

- Datepart este unitatea de masura


- Startdate este data de inceput
- Enddate este data de sfarsit

Exemplu: Sa se determine la ce varsta s-a angajat fiecare persoana din companie.

select
empid
,lastname
,firstname
,datediff(yyyy,birthdate,hiredate) Varsta
from Training.hr.Employees

Unitatea de masura care poate fi atribuita functiei DATEDIFF este:

Functia DATEADD determina data calendaristica peste o anumita perioada, perioada


exprimata in ani, luni, zile, trimestre, saptamani etc.

Sintaxa functiei DATEADD:

Dateadd(datepart, interval, startdate), unde:

46
- Datepart este unitatea de masura
- Interval reprezinta perioada
- Startdate este data de inceput

Exemplu: Sa se determine pentru fiecare angajat anul in care va primi un bonus de fidelitate
stiind ca acest bonus se primeste la 5 ani de la angajare.

select
empid
,lastname
,firstname
,hiredate
,dateadd(yyyy,5,hiredate) Data_Bonus
,year(dateadd(yyyy,5,hiredate)) An_Bonus
from Training.hr.Employees

47
X. Functii de text: CHARINDEX, SUBSTRING, LEN. Operatorul de
concatenare

Functia CHARINDEX – identifica pe ce pozitie se regaseste caracterul cautat. Atunci cand


argumentul pentru care se cauta pozitia este un sir de caractere, functia returneaza pozitia
primului caracter din sirul cautat.

Exemplu: Sa se identifice pe ce pozitie se regaseste caracterul virgula din coloana


contactname, tabela customers.

SELECT
[custid]
,[companyname]
,[contactname]
,charindex(',',contactname,1) Pozitie_Virgula
FROM [Training].[Sales].[Customers]

Functia SUBSTRING – extrage dintr-un sir de caractere, incepand cu pozitia specificata, un


numar de catactere.

Exemplu: Sa se extraga in doua coloane separate numele si prenumele clientilor, din coloana
contactname.

SELECT
[custid]
,[companyname]
,[contactname]
,charindex(',',contactname,1) Pozitie_Virgula
,substring(contactname,1,charindex(',',contactname,1)-1) LastName
,substring(contactname,charindex(',',contactname,1)+1,len(contactname)-
charindex(',',contactname,1)) FirstName
FROM [Training].[Sales].[Customers]

48
Rezultatul interogarii – 91 de randuri.

Obs: Primul pas a fost indetificarea pozitiei virgulei. Pentru a extrage LastName, se vor extrage
toate caracterele situate inaintea virgulei. Pentru a extrage FirstName, se vor extrage toate
caracterele situate dupa virgula.

Functia LEN determina lungimea unui sir de caratere.

Exercitii:

Baza de date Bank:

1. Sa se determine pentru fiecare client, tipul contului dupa urmatoarea regula:


o Daca balanta este intre 0 si 600 se va afisa textul <=600
o Daca balanta este intre 600 si 1500 se va afisa (600-1500]
o Daca balanta este peste 1500 se va afisa >1500

Rezultat interogare:

2. Sa se modifice interogarea anterioara astfel incat, pentru fiecare client sa fie afisate cate
conturi se regasesc in fiecare interval mentionat.

Rezultat interogare:

49
3. Sa se determine pentru fiecare client data de procesare a tranzactiei, stiind ca aceasta
va fi procesata la 5 zile de la data efectuarii tranzactiei.

Rezultat interogare:

4. Sa se determine pentru fiecare client data de procesare a tranzactiei, stiind ca:


o Tranzactiile de tip Comision se proceseaza la o saptamana de la data efectuarii
tranzactiei
o Tranzactiile de tip Plata Salariu se proceseaza la o luna de la data efectuarii
tranzactiei
o Restul tranzactiilor se proceseaza la 5 zile de la data efectuarii tranzactiei

50
Baza de date Training:

5. Sa extraga din tabela Shippers numele celor 3 companii: GVSUA, ETYNR, ZHISN.

Rezultatul interogarii:

6. Sa se determine pentru fiecare comanda, numarul de zile de la data efectuarii comenzii


pana la data livrarii comanzii. In cazul in care numarul de zile determinat este mai mare
de 10 sa se afiseze textul Termen Depasit, altfel sa se afiseze textul La Termen.

Rezultat interogare:

51
XI. Tabele temporare. CTE

Tabele temporare

SQL Server utilizeaza doua tipuri de tabele temporare: locale si globale. Ambele tipuri de tabele
sunt stocate in baza de date tempdb.

Tabelele temporare locale sunt prefixate cu # (exemplu: #mytable), iar tabelele temporare
globale sunt prefixate cu ## (exemplu: ##mytable).

Tabelele temporare locale sunt vizibile doar pe parcursul sesiunii unui singur user. Dupa
incheierea sesiunii, acestea sunt sterse.

Tabelele temporare gloable sunt vizibile pentru toate sesiunile si pentru toti userii. Se sterg
automat dupa inchiderea ultimei sesiuni in care sunt folosite.

Tabelele temporare (atat locale, cat si globale) se comporta la fel ca orice tabel permanent din
baza de date, exceptand baza de date unde sunt stocate (tempdb) si faptul ca acestea sunt
sterse automat la inchiderea sesiunii.

Exemplu: Sa se determine intr-o tabela temporara toti clientii din Londra si pentru acestia prima
tranzactie efectuata. Pentru tranzactiile extrase, sa se determine total discount (discount *
cantitate * pret) si total incasari (cantitate * pret).

SELECT c.custid
,c.city
,min(o.orderid) Min_OrderId
into #minorder
FROM [Training].[Sales].[Customers] c
inner join Training.Sales.Orders o on o.custid=c.custid
where c.city='London'
group by
c.custid
,c.city

52
select
m.*
, sum(od.discount * od.qty * od.unitprice) Total_Discount
, sum(od.qty * od.unitprice) Total_Valoare
from #minorder m
inner join Training.Sales.OrderDetails od on od.orderid=m.Min_OrderId
group by
m.custid
,m.city
,m.Min_OrderId

Obs: Tabela #minorder este o tabela temporara locala.

Exemplu: Sa se determine acelasi lucru ca mai sus, dar sa se utilizeze tabela temporara globala
##minorder.

SELECT c.custid
,c.city
,min(o.orderid) Min_OrderId
into ##minorder
FROM [Training].[Sales].[Customers] c
inner join Training.Sales.Orders o on o.custid=c.custid
where c.city='London'
group by
c.custid
,c.city

select
m.*
, sum(od.discount * od.qty * od.unitprice) Total_Discount
, sum(od.qty * od.unitprice) Total_Valoare
from ##minorder m
inner join Training.Sales.OrderDetails od on od.orderid=m.Min_OrderId
group by
m.custid
,m.city
,m.Min_OrderId

53
Obs: Diferenta dintre cele doua tabele: #minorder, ##minorder este faptul ca cea dea doua
tabela poate fi vizualizata si intr-o alta sesiune.

Obs: Cele doua tabele se pot vedea in baza de date tempdb.

Exercitii:

Baza de date Bank:

1. Sa se determine intr-o tabela temporara locala conturile cu balanta cea mai mica. Pentru
aceste conturi sa se extraga toate tranzactiile efectuate.
2. Sa se determine intr-o tabela temporara globala conturile de tip Credit. Pentru aceste
conturi sa se determine toate tranzactiile din 2010 si 2011.
3. Sa se determine intr-o tabela temporara locala prima tranzactie efectuata de catre
fiecare client. Pentru aceste tranzactii, sa se determine separat valoarea tranzactiilor si
tipul acestora.

CTE – Common Table Expression – este un concept similar cu tabelele derivate. Tabele CTE
sunt vizibile doar pe parcursul rularii statementului in care sunt definite. Un tabel de tip expresie
este format din 3 parti:

- Interogarea din interior


- Numele asignat interogarii si numele coloanelor
- Interogarea din exterior

Sintaxa CTE:

WITH nume_CTE as

( interogrea din interior)

54
interogarea din exterior

Exemplu: Sa se determine pentru fiecare client, contul cu balanta cea mai mare.

with CTE_bal
as
nume
(select
idclient,
max(balanta) balanta
from bank.dbo.conturi
group by Interogrea din interior
idclient
)

select
c.cont,
c.idclient,
c.Balanta
from bank.dbo.conturi c Interogarea din exterior
inner join cte_bal cc on
c.Balanta=cc.balanta and
c.IdClient=cc.IdClient

Exercitii:

1. Sa se determine pentru toti clientii cu suma totala comandata de peste 1000, toate
comenzile.

Rezolvare:

with cte_cust
as
(
select
c.custid
,sum(od.qty*od.unitprice) Total_Comenzi
from Training.Sales.Customers c
inner join Training.Sales.Orders o on o.custid=c.custid
inner join Training.Sales.OrderDetails od on od.orderid=o.orderid
group by c.custid
having
sum(od.qty*od.unitprice)>1000
)

55
select
o.*
from cte_cust cc
inner join Training.Sales.Orders o on o.custid=cc.custid

Rezultat interogare – 816 randuri.

56
XII. Utilizare operatorilor pentru seturi de date: UNION ALL, UNION,
INTERSECT, EXCEPT

Operatorii UNION ALL si UNION

UNION ALL: opereaza intre doua sau mai multe seturi de date. UNION ALL uneste rezultatele
mai multor seturi date si pastreaza inregistrarile multiplicate.

Exemplu: Sa se determine toate orasele, regiunile si tarile clientilor si ale angajatilor.

select
city
,region
,country
from Training.Sales.Customers

union all

select
city
,region
,country
from Training.hr.Employees

Rezultat interogare – 100 de randuri.

Obs: Structura celor doua interogari este identica. Rezultatul final al reuniunii rezultatelor celor
doua interogarii contine inregistrari care se multiplica.

UNION: opereaza intre doua sau mai multe seturi de date. UNION uneste rezultatele mai multor
seturi date si elimina inregistrarile multiplicate.

57
Exemplu: Sa se determine toate orasele, regiunile si tarile clientilor si ale angajatilor.

select
city
,region
,country
from Training.Sales.Customers

union

select
city
,region
,country
from Training.hr.Employees

Rezultat interogare – 71 de randuri.

INTERSECT – operatorul returneaza inregistrarile comune dintre doua sau mai multe seturi de
date.

Exemplu: Sa se determine toate orasele, regiunile si tarile comune ale clientilor si ale
angajatilor.

select
city
,region
,country
from Training.Sales.Customers

intersect

select
city
,region
,country
from Training.hr.Employees

58
EXCEPT – operatorul returneaza diferenta dintre doua seturi de date, inregistrarile continute de
primul set de date care nu se regasesc in al doilea set.

Exemplu: Sa se determine toate orasele, regiunile si tarile clientilor din care nu fac parte
angajatii.

select
city
,region
,country
from Training.Sales.Customers

except

select
city
,region
,country
from Training.hr.Employees

Rezultat interogare – 66 de randuri.

Exercitii suplimentare: baza de date Training

1. Sa se determine pentru fiecare tara a clientului: nr de comenzi plasate, nr de comenzi livrate,


Vanzari.
Raportul va avea urmatoarea structura:
Country_customer / no_orders / no_delivered_orders / sales
Hint:
Pentru a determina in acelasi script si nr de comenzi, si nr de comenzi livrate, este necesara o
prelucrare suplimentara in select:

• Calcul comenzi livrate: in cazul in care shippeddate is not null, atunci se va afisa
orderid, altfel nu se va afisa nimic. Peste orderid-urile determinate, se va aplica
functia count. Atentie, fiind join cu orderdetails, se va calcula count (distinct de case-
ul implementat mai sus)

Rezultatul final:

59
country no_orders no_delivered_orders

Argentina 16 14

Austria 40 38

Belgium 19 19

Brazil 83 81

Canada 30 29
(nu sunt afisate toate tarile)

22 randuri este rezultatul final

select
c.country as Customer_Country,
count(distinct o.orderid) as No_orders,
count(distinct case when o.shippeddate is not null then o.orderid
end) as No_delivered_orders,
sum(od.qty*od.unitprice) as sales
from sales.Customers as c
inner join sales.Orders as o on c.custid=o.custid
inner join sales.OrderDetails as od on o.orderid=od.orderid
group by
c.country

2. Sa se determine toate comenzile plasate pana la sfarsitului lunii anterioare si valoarea lor.
Rezultatul va avea urmatoarele coloane:
Orderid / orderdate / sales
Pornind de la rezultatul anterior, sa se determine cate comenzi si total sales pe urmatoarele
intervale:
Clasificare
1.<=1000
2.<=5000
3.<=10000
4.>10000

Hinturi:
Pas 1:
- Se va cauta functia care determina ultima zi din luna.
- Luna anterioara se va calcula dinamic, pornind de la azi, iar azi este data de o functie
- ! Atentie ca functia care da data curenta, arata si timpul si trebuie eliminat timpul, iar apoi
calculata ultima zi din luna anterioara
- Rezultatul extras (Sa se determine toate comenzile plasate pana la sfarsitului lunii anterioare
si valoarea lor) poate fi stocat intr-o tabela temporara locala sau globala (sau se poate folosi
un CTE)

60
Pas 2:
- Rezultatul anterior este folosit in urmatorul script pentru a extrage raportul final
Rezultatul final este:

Clasificare no_orders total_sales

1.<=1000 411 198,407

2.<=5000 381 827,636

3.<=10000 24 158,089

4.>10000 14 170,328
; with cte_comenzi as
(select
o.orderid,
o.orderdate,
sum(od.qty*od.unitprice) as sales
from sales.Orders as o
inner join sales.OrderDetails as od on o.orderid=od.orderid
where o.orderdate<=EOMONTH(getdate(),-1)
group by
o.orderid,
o.orderdate)

select
case
when sales<=1000 then '1.<=1000'
when sales<=5000 then '2.<=5000'
when sales<=10000 then '3.<=10000'
else '4.>10000' end as Clasificare,
count(orderid) as nr_comenzi,
sum(sales) as total_vanzari
from cte_comenzi
group by
case
when sales<=1000 then '1.<=1000'
when sales<=5000 then '2.<=5000'
when sales<=10000 then '3.<=10000'
else '4.>10000' end
order by Clasificare

61
XIII. Creare baza de date. Creare tabele. Constrangeri tabele.
Diagrama baza de date.

Creare baza de date

O baza de date reprezinta un ansamblu de date, organizat coerent, structurat cu o redundanta


minima si accesibile cat mai multor utilizatori in acelasi timp. Toate aceste date sunt organizare
in tabele. Cel mai utilizate tipuri de baze de date sunt cele relationale, in care informatiile sunt
organizate in mai multe tabele intre care exista legaturi (relatii).

Exemplu: Se va considera ca business o companie de turism. Business-ul companiei este


rezumat astfel:

- Entitati: clienti, hoteluri, rezervari

Flow de business:

- un client suna departamentul Call Center pentru a primi o oferta de concediu=> Clientul
este stocat in tabela Clienti
- Agentul din Call Center creeaza o rezervare pentru propunerea catre client=>
Rezervarea este creata si stocata in tabela Orders
- Clientul confirma sau nu rezervarea. Daca va confirma rezervarea => Rezervarea
confirmata este stocata in tabela Orders_details
- Daca se confirma rezervarea, atunci se stiu detaliile despre rezervare=> tabela Hotels,
tabela Cities, tabela Countries

Sintaxa creare baza de date:


CREATE DATABASE Reservations;

Conform exemplului de business de mai sus, se pot identifica urmatorele tabele: Customers,
Countries , Cities, Hotels, Orders, Orders_details.

Creare tabele

Sintaxa creare tabele:

- Pentru a defini un tabel intr-o baza de date sunt necesare urmatoarele:

62
o Nume tabel
o Coloanele din tabela: nume coloane, tipuri de date pentru fiecare coloana, daca
fiecare coloana admite sau nu NULL, primary key pentru fiecare tabela.

Sintaxa creare tabela:


USE [Reservations]
GO

CREATE TABLE dbo.customers


(
[idcustomer] [int] NOT NULL,
[name] [nvarchar](50) NULL,
[idcountry] [int] NOT NULL,
CONSTRAINT [PK_customers] PRIMARY KEY (idcustomer)
)

Obs: Coloanele idcustomer si idcountry nu accepta NULL. Cheia primara (PK) pentru tabela
Customers este idcustomer. Coloanele pentru care se va seta PK nu accepta NULL. Pentru o
tabela se poate defini cel mult o cheie primara.

In mod similar se creeaza si celelalte tabele mentionate mai sus.

USE Reservations
GO

CREATE TABLE dbo.cities


(
cityid int NOT NULL,
cityname nvarchar(50) NULL,
idcountry int NOT NULL,
CONSTRAINT PK_cities PRIMARY KEY (cityid)
)

GO

CREATE TABLE dbo.countries


(
idcountry int NOT NULL,
name nvarchar(255) NULL
CONSTRAINT PK_countries PRIMARY KEY (idcountry)
)
GO

CREATE TABLE dbo.hotels


(
idhotel int NOT NULL,

63
name nvarchar(50) NULL,
idcity int NOT NULL,
stars int NULL,
CONSTRAINT PK_hotels PRIMARY KEY (idhotel)
)

GO

CREATE TABLE dbo.orders


(
idorder int NOT NULL,
idcustomer int NOT NULL,
creationdate datetime NULL,
CONSTRAINT PK_orders PRIMARY KEY (idorder)
)

GO

CREATE TABLE dbo.orders_details


(
idorder int NOT NULL,
totalprice money NULL,
startdate datetime NULL,
enddate datetime NULL,
idhotel int NOT NULL,
rooms int NULL,
idtyperoom int NOT NULL,
CONSTRAINT PK_orders_details PRIMARY KEY (idorder)

GO

CREATE TABLE dbo.type_room


(
idtyperoom int NOT NULL,
description nvarchar(50) NULL,
CONSTRAINT PK_type_room PRIMARY KEY (idtyperoom)
)

Alterare tabele

Un tabel odata creat poate fi modificat utilizand comanda ALTER. In acest mod pot fi adaugate,
sterse, modificate coloane.

Exemple:

1) Sa se adauge o coloana noua in tabela Customers cu numele Address, de tip


varchar(100).

alter table Reservations.dbo.customers

64
add Address varchar(100)

2) Sa se modifice tipul coloanei Address din tabela Customers in varchar(150).

alter table Reservations.dbo.customers


alter column Address varchar(150)

3) Sa se stearga coloana Address din tabela Customers.

alter table Reservations.dbo.customers


drop column Address

Constrangeri tabele

1) NOT NULL: indica daca o coloana accepta sau nu NULL


2) UNIQUE: asigura daca datele dintr-o coloana sunt unice sau nu
3) PRIMARY KEY: asigura ca o coloana/ un ansamblu de coloane contine/contin date
unice. Coloana sau ansamblu de coloane nu accepta NULL.
4) FOREIGN KEY: asigura integritatea referentiala a datelor dintr-o tabela (Exemplu:
Tabela Orders nu poate contine rezervari pentru clienti care nu sunt prezenti in tabela
Customers)
5) CHECK: asigura ca valorile dintr-o coloana indeplinesc o conditie specificata (Exemplu:
Id-ul de rezervare este maxim 10000)
6) DEFAULT: valoarea default pentru o coloana

Adaugare constrangeri tabele existente

Exemple:

1) Sa se modifice tabela Customers astfel incat, campul Name sa nu accepte NULL.

alter table Reservations.dbo.customers


alter column Name nvarchar(50) NOT NULL

Obs: Daca tabela Customers contine deja date, iar coloana Name are deja null-uri, atunci
adaugarea constragerii NOT NULL nu va functiona. Mai intai se vor completa NULL-urile

65
existente si apoi se va aplica constrangerea de NOT NULL pentru viitorii clienti inserati in
tabela.

2) Sa se modifice tabela Hotels, astfel incat, campul idCity sa admita doar date unice.

alter table Reservations.dbo.Hotels


add constraint AC_City UNIQUE (idcity)

OBS: Adaugarea constrangerii de UNIQUE pentru IdCity inseamna din punct de vedere
business ca 2 hoteluri nu pot fi din acelasi oras. De exemplu, un lant hotelier are un singur hotel
in fiecare oras, Ramada ar putea fi un exemplu in acest sens.

3) Sa se stearga primary key-ul din tabela Cities. Sa se adauge primary key pe tabela
Cities.

alter table Reservations.dbo.Cities


drop constraint PK_cities

alter table Reservations.dbo.Cities


add constraint PK_cities primary key (cityid)

4) Pentru fiecare tabela de mai sus sa se stabileasca Foreign key.

ALTER TABLE Orders


ADD FOREIGN KEY (idcustomer) REFERENCES Customers(idcustomer)

ALTER TABLE Orders_Details


ADD FOREIGN KEY (idorder) REFERENCES Orders(idorder)

ALTER TABLE Orders_Details


ADD FOREIGN KEY (idhotel) REFERENCES Hotels(idhotel)

ALTER TABLE Hotels


ADD FOREIGN KEY (idcity) REFERENCES Cities(cityid)

ALTER TABLE Cities


ADD FOREIGN KEY (idcountry) REFERENCES Countries(idcountry)

ALTER TABLE Customers


ADD FOREIGN KEY (idcountry) REFERENCES Countries(idcountry)

5) Sa se adauge constrangerea de CHECK astfel incat, in tabela Hotels, campul Stars sa


nu contina valori mai mari de 5.

66
alter table Reservations.dbo.Hotels
add constraint Ch_stars CHECK (stars<=5)

6) Sa se modifice tabela Orders_details, astfel incat coloana rooms sa aiba valoarea


default 1.

alter table Reservations.dbo.Orders_details


add constraint df_rooms default (1) for rooms

Creare tabele cu constrangeri

Exemple:

1) tabela Customers - campul Name sa nu accepte NULL.

CREATE TABLE dbo.customers1


(
[idcustomer] [int] NOT NULL,
[name] [nvarchar](50) NOT NULL,--1)tabela Customers-campul Name sa nu accepte NULL
[idcountry] [int] NOT NULL,
CONSTRAINT [PK_customers1] PRIMARY KEY (idcustomer)
)

2) tabela Hotels - campul idCity sa admita doar date unice.


3) constrangerea de CHECK in tabela Hotels, - campul Stars sa nu contina valori mai mari
de 5.

CREATE TABLE dbo.hotels1


(
idhotel int NOT NULL,
name nvarchar(50) NULL,
idcity int NOT NULL,
stars int NULL,
CONSTRAINT PK_hotels1 PRIMARY KEY (idhotel),
CONSTRAINT UNK_hotels1 UNIQUE (idcity), -- 2) tabela Hotels - campul idCity sa
admita doar date unice.
CONSTRAINT Ch_hotels1 Check (stars<=5) -- 3) constrangerea de CHECK in tabela
Hotels, - campul Stars sa nu contina valori mai mari de 5.
)
4) tabela Orders_details - coloana rooms sa aiba valoarea default 1.

CREATE TABLE dbo.orders_details1


(
idorder int NOT NULL,
totalprice money NULL,
startdate datetime NULL,

67
enddate datetime NULL,
idhotel int NOT NULL,
rooms int NULL default 1,
idtyperoom int NOT NULL,
stars int NULL,
CONSTRAINT PK_orders_details1 PRIMARY KEY (idorder)
)

Diagrama baza de date

Creare unei diagrame de baze de date se realizeaza in modul Design:

- Object Explorer / baza de date Reservations / click dreapta Database Diagrams / New
Database Diagram

- se adauga tabelele utilizate in Diagrama

Obs: Daca pentru fiecare tabela au fost adaugate FOREIGN KEYS, atunci digrama si
relatiile dintre tabele se creaza implicit.

68
Obs: Daca pentru fiecare tabela nu au fost adaugate FOREIGN KEYS, atunci digrama si
relatiile dintre tabele trebuie create de catre utilizator.

Crearea FOREIGN KEY-urilor se realizeaza prin tragere de la PK la campul de legatura


(exemplu: idcountry din Countries catre idcountry din Customers)

69
Obs: campurile conectate trebuie sa fie identice ca si: tip, contrangeri. Numele nu este
obligatoriu sa fie identic, insa best practice este sa se pastreze acelasi nume.

70
Exercitii:

1. Sa se creeze o baza de date cu numele CarRental.


2. Sa se creeze urmatoarele tabele in baza de date CarRental cu urmatoarele
constrangeri:

Locatii

IdLocatie Int Nu admite NULL PK


Oras Varchar(50)
Judet Varchar(50)

Clienti

IdClient Int Nu admite NULL PK


Denumire Varchar(100)
IdLocatie Int Nu admite NULL FK cu referinta catre tabela Locatii

Masini

IdMasina Varchar(20) Nu admite NULL PK


Marca Varchar(50)
AnFabricatie Int

Angajati

71
IdAngajat Int Nu admite NULL PK
Denumire Varchar(100)
Functie Varchar(50)
IdLocatie Int Nu admite NULL FK cu referinta catre tabela
IdLocatie

Contracte

IdContract Int Nu admite NULL PK


IdClient Int Nu admite NULL FK cu referinta catre tabela Clienti
IdMasina Varchar(20) Nu admite NULL FK cu referinta catre tabela Masini
StartDate Datetime
EndDate DateTime
Valoare Decimal(10,4)
IdAngajat Int Nu admite NULL FK cu referinta catre tabela Angajati,
Default value 1 (managerul firmei)

3. Sa se defineasca diagrama bazei de date.

Proiect: Sa se construiasca o baza de date (business la alegere) cu urmatoarele caracteristici:

- Minim 4 tabele

72
- Constrangeri adaugate asupra coloanelor
- Diagrama bazei de date

73
XIV. Setul de comenzi T-SQL: INSERT, UPDATE, DELETE, TRUNCATE
INSERT

T-SQL detine mai multe metode de a insera date:

- INSERT Values
- INSERT Select
- INSERT Exec – se va discuta la modulul SQL Programming For Developers, unde sunt
prezentate Procedurile Stocate si comanda „exec”
- SELECT Into

INSERT Values

Exemplu: Sa se insereze doi clienti noi in tabela Clienti din baza de date Bank. Primul client
inserat va avea id-ul 400 si se va numi Client 4. Cel de-al doilea client inserat va avea id-ul 500
si se va numi Client 5.

insert into Bank.dbo.clienti values (400,'Client 4')


insert into Bank.dbo.clienti values (500,'Client 5')

(1 row(s) affected)

(1 row(s) affected)

INSERT Select

Exemplu: Sa se creeze o tabela temporara cu numele ##clienti care va avea doua coloane:
IdClient int not null si Nume_Client varchar(20). Campul IdClient va avea constrangerea de PK.
Sa se insereze toti clientii din tabela Bank.dbo.Clienti in tabela ##clienti.

create table ##clienti


(IdClient int not null,
Nume_Client varchar(20),
constraint PK_Clt primary key (IdClient)
)

insert into ##Clienti


(IdClient, Nume_Client)
select
IdClient, Nume
from Bank.dbo.clienti

74
(5 row(s) affected)

Obs: Utilizarea sintaxei INSERT Select impune urmatoarele reguli:

- Se specifica coloanele din cadrul tabelei in care se vor insera date.


- Se specifica coloanele din cadrul selectului.

Obs: Pentru verificare se selecteaza informatiile din tabela ##clienti.

select * from ##clienti

SELECT Into

Utilizarea metodei SELECT Into conduce la crearea unei tabele noi.

Exemplu: Sa se insereze toate conturile clientilor: Client 1 si Client 2 intr-o tabela temporara
locala. Odata cu conturile se va afisa si numele clientului.

select
c.Nume
,cc.IdClient
,cc.Cont
,cc.Balanta
into #conturi_clienti
from bank.dbo.clienti c
inner join bank.dbo.conturi cc on c.IdClient=cc.IdClient
where c.nume in ('Client 1','Client 2')

(6 row(s) affected)

Obs: Pentru verificare se selecteaza toate informatiile din tabela #conturi_clienti

select * from #conturi_clienti

75
UPDATE

Comanda UPDATE modifica datele in tabelele existente.

Vom construi 3 tabele, copii ale tabelelor existente Customers, Orders si OrderDetails:
MyCustomers, MyOrders, MyOrderDetails
Construirea celor 3 tabele a fost realizata utilizand comanda SELECT Into.

Use Training;
GO

SELECT * INTO Sales.MyCustomers


FROM Sales.Customers;
ALTER TABLE Sales.MyCustomers
ADD CONSTRAINT PK_MyCustomers PRIMARY KEY(custid);
(91 row(s) affected)

SELECT * INTO Sales.MyOrders


FROM Sales.Orders;
ALTER TABLE Sales.MyOrders
ADD CONSTRAINT PK_MyOrders PRIMARY KEY(orderid);
(830 row(s) affected)

SELECT * INTO Sales.MyOrderDetails


FROM Sales.OrderDetails;
ALTER TABLE Sales.MyOrderDetails
ADD CONSTRAINT PK_MyOrderDetails PRIMARY KEY(orderid, productid);
(2155 row(s) affected)

Sintaxa:

UPDATE tabela

SET Col1=expresia1,

Col2=expresia2

WHERE conditii

76
Randurile care vor fi evaluate la TRUE in ceea ce priveste clauza WHERE vor fi updatate. Daca
nu este specificata clauza WHERE, atunci vor fi updatate toate randurile din tabela specificata.

Exemplu: Sa se modifice discountul pentru factura cu numarul 10251 astfel incat, discountul va
fi crescut cu 5%.

- Verificam pentru factura specificata, care este discountul la nivel de produs

select *
from Sales.MyOrderDetails
where orderid=10251

- Updatam randurile cu +0.05

update sales.MyOrderDetails
set discount=discount+0.05
where orderid=10251
(3 row(s) affected)

- Verificam factura specificata, discountul dupa update

UPDATE utilizand JOIN-uri

Exemplu: Sa se modifice discountul adaugand 5% pentru toate facturile clientilor din Norway.

- Verificam pentru clientii din Norway, care vor fi randurile updatate

select
od.orderid
,od.productid
,od.discount
,c.custid
,c.companyname

77
,c.country
from Sales.MyOrderDetails od
inner join sales.MyOrders o on o.orderid=od.orderid
inner join sales.MyCustomers c on c.custid=o.custid
where c.country='Norway'

Obs: este un singur client cu mai multe comenzi, fiecare comanda avand un numar de produse
cu 0 discount.

- Se updateaza randurile selectate

update od
set od.discount=od.discount+0.05
from Sales.MyOrderDetails od
inner join sales.MyOrders o on o.orderid=od.orderid
inner join sales.MyCustomers c on c.custid=o.custid
where c.country='Norway'

- Verificam randurile updatate

select
od.orderid
,od.productid
,od.discount
,c.custid
,c.companyname
,c.country
from Sales.MyOrderDetails od
inner join sales.MyOrders o on o.orderid=od.orderid
inner join sales.MyCustomers c on c.custid=o.custid
where c.country='Norway'

78
DELETE si TRUNCATE

T-SQL detine doua comenzi pentru stergerea datelor dintr-o tabela: DELETE si TRUNCATE

DELETE

Comanda DELETE sterge fie datele dintr-o tabela in intregime, fie doar anumite randuri care
sunt evaluate la TRUE conform uneia sau mai multor conditii.

Exemplu: Sa se stearga toate randurile din tabela MyOrderDetails unde productid=11 (se
presupune ca acest produs a fost adaugat dintr-o eroare pe anumite facturi si trebuie sters).

delete
from Sales.MyOrderDetails
where productid=11

(38 row(s) affected)

Obs: Se verifica daca mai sunt comenzi cu productid=11

select *
from Sales.MyOrderDetails
where productid=11

79
Exemplu: Sa se stearga toate randurile din tabela MyOrderDetails

delete
from Sales.MyOrderDetails

(2117 row(s) affected)

DELETE utilizand JOIN-uri

Exemplu: Sa se stearga toate comenzile clientilor din Norway.

delete o
from sales.MyOrders o
inner join sales.MyCustomers c on c.custid=o.custid
where c.country='Norway'

(6 row(s) affected)

Obs: Se verifica daca mai sunt comenzi pentru clientii din Norway.

select *
from sales.MyOrders o
inner join sales.MyCustomers c on c.custid=o.custid
where c.country='Norway'

Obs: Clientii din Norway nu au fost stersi, doar comenzile acestora au fost sterse.

select *
from sales.MyCustomers
where country='Norway'

Daca se doreste si stergerea clientilor din Norway, atunci, dupa stergerea comenzilor se poate
rula comanda de delete asupra tabelei MyCustomers cu conditia: country='Norway'

TRUNCATE

80
Comanda TRUNCATE sterge toate randurile dintr-o tabela. Nu permite conditii pentru a sterge
doar anumite randuri.

Exemplu: Sa se stearga toate comenzile.

truncate table sales.MyOrders

Command(s) completed successfully.

Obs: Diferentele dintre DELETE si TRUNCATE sunt:

- DELETE permite stergerea anumitor randuri dintr-o tabela, TRUNCATE sterge toate
datele dintr-o tabela
- TRUNCATE este mai rapida decat DELETE, pentru ca scrierea in Transaction Log se
face doar pentru paginile dealocate, in timp ce DELETE scrie in Transaction Log datele
care sunt sterse
- DELETE nu reseteaza identity. TRUNCATE reseteaza identity
- DELETE sterge utilizand JOIN-uri, ceea ce inseamna ca tine cont de FK. TRUNCATE
nu este permisa daca o tabela refrentiaza catre alta tabela
- DELETE are nevoie pentru user de dreptul de DELETE. TRUNCATE are nevoie pentru
user de dreptul de ALTER

Exercitii: INSERT, UPDATE, DELETE, TRUNCATE

1. Sa se insereze doua conturi pentru clientul cu id-ul 400 in tabela Bank.dbo.Conturi:


400 999910 1 5500
400 999911 1 NULL

2. Sa se insereze toate conturile din tabela Bank.dbo.Conturi intr-o tabela noua


MyAccounts
3. Sa se stearga toate conturile cu balanta NULL din tabela MyAccounts.
4. Sa se stearga toate conturile din tabela MyAccounts.
5. Sa se insereze in tabela MyAccounts toate conturile cu balanta peste 5000.
6. Sa se modifice tipul conturilor din tabela MyAccounts astfel incat toate sa fie de tip 1.
7. Sa se truncheze tabela MyAccounts

81
XV. Creare VIEW-uri

Creare VIEW

VIEW-urile sunt obiecte ale bazei de date similare tabelelor. Cu ajutorul unui VIEW se pot
prezenta date dintr-unul sau mai multe tabele. Intr-un view se poate pastra logica de extragere
a datelor, astfel incat utilizatorul view-ului sa nu fie nevoit sa o retina.

Exemplu: Sa se creeze un view in care se va determina: pentru fiecare an al comenzilor, suma


cantitatilor.

create view Sales.Qty_Orders


with schemabinding
as

select
year(o.orderdate) Year_Order,
sum(od.qty) Total_Qty

from sales.Orders o
inner join sales.OrderDetails od on od.orderid=o.orderid

group by
year(o.orderdate)

Obs:

a) Daca se ruleaza selectul din interiorul view-ului, rezultatul este:

b) Daca se extrag datele din view, rezultatul este:


select * from Sales.Qty_Orders

c) View-ul creat se comporta la fel cu un tabel: se pot filtra datele, se pot face join-uri cu
alte tabele:

82
select *
from Sales.Qty_Orders
where Year_Order<>2006

d) Optiunea WITH SCHEMABINDING protejeaza view-ul de modificari in cadrul tabelului /


tabelelor. Daca sunt modificari de efectuat in tabela / tabelele implicate in view, atunci
primul pas este de a sterge view-ul si apoi se pot modifica obiectele implicate in view.
- Daca se modifica tipul coloanei qty dim smallint in int:

alter table sales.OrderDetails


alter column qty int not null

The object 'Qty_Orders' is dependent on column 'qty'.


Msg 4922, Level 16, State 9, Line 1

Modificare VIEW

Modificarea / alterarea unui view se realizeaza in mod similar cu tabelele, utilizand comanda
ALTER.

Exemplu: Sa se modifice view-ul creat anterior (Sales.Qty_Orders) astfel incat informatiile sa fie
si la nivel de client (companyname).

alter view Sales.Qty_Orders


with schemabinding
as

select
c.companyname,
year(o.orderdate) Year_Order,
sum(od.qty) Total_Qty

from sales.Orders o
inner join sales.OrderDetails od on od.orderid=o.orderid
inner join sales.Customers c on c.custid=o.custid

group by
c.companyname,
year(o.orderdate)

Verificare

select * from Sales.Qty_Orders

83
Stergere VIEW

Comanda pentru a sterge un view din baza de date este: DROP view nume_view.

Exemplu: Sa se stearga view-ul Sales.Qty_Orders

drop view Sales.Qty_Orders

Command(s) completed successfully.

Exercitii:

1. Sa se creeze un view cu schemabinding in baza de date Bank. View-ul extrage: pentru


fiecare client si cont, tranzactiile diferite de tipul 1.
2. Sa se modifice tipul coloanei Nume client din nvarchar(255) in nvarchar(500).

Rezolvare:

1.

use bank;
go

create view dbo.Conturi_Tranz_Clienti


with schemabinding

as
select
c.Nume
,cc.Cont
,cc.Balanta
,t.IdTranzactie
,t.DataTranzactie
,t.Valoare

from dbo.clienti c
inner join dbo.conturi cc on c.IdClient=cc.IdClient
inner join dbo.tranzactii t on t.Cont=cc.Cont
where t.IdTipTranzactie<>1
2.

alter table bank.dbo.clienti


alter column Nume nvarchar(500)

Msg 5074, Level 16, State 1, Line 2

84
The object 'Conturi_Tranz_Clienti' is dependent on column 'Nume'.
Msg 4922, Level 16, State 9, Line 2
ALTER TABLE ALTER COLUMN Nume failed because one or more objects access this column.

Corect:

use bank;
go

drop view dbo.Conturi_Tranz_Clienti


alter table bank.dbo.clienti
alter column Nume nvarchar(500)

create view dbo.Conturi_Tranz_Clienti


with schemabinding

as

select
c.Nume
,cc.Cont
,cc.Balanta
,t.IdTranzactie
,t.DataTranzactie
,t.Valoare

from dbo.clienti c
inner join dbo.conturi cc on c.IdClient=cc.IdClient
inner join dbo.tranzactii t on t.Cont=cc.Cont
where t.IdTipTranzactie<>1

3. Sa se creeze un view in baza de date Bank astfel:


- View-ul extrage pentru fiecare client:
o Suma balantelor conturilor de tip credit
o Suma balantelor conturilor de tip debit
4. Sa se modifice view-ul creat la punctul 3 astfel incat sa fie exclus clientul: Client 2. Sa se
verifice view-ul.
5. Sa se creeze un view in baza de date Bank astfel:
- View-ul va determina la nivel de nume client, cont si tipcont:
o Suma balantelor pe cont
o Suma valorilor tranzactiilor
o Numarul de tranzactii
o Nu vor fi considerate tranzactiile de tip Plata Utilitati si nici tranzactiile de tip
Transfer din.

85
- Sa se extraga din view doar informatiile pentru conturile de tip Credit.
6. Sa se modifice view-ul creat la punctul 5 astfel incat conturile de tip Debit sa nu fie
considerate. Sa se verifice view-ul.

86

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