Folosirea functiei RANK() in SQL Server

Configurare noua (How To)

Situatie

Am observat, in timp, ca sunt cateva functii de sql foarte putin cunoscute, dar care, in unele cazuri, ne pot usura foarte mult munca.Din acest motiv am sa prezint si sa explic cateva dintre ele.
Una dintre cele mai putin cunoscute functii este RANK(). Aceasta functie insa ne poate ajuta foarte mult in anumite situatii.

Spre exemplu, daca ni se cere sa scoatem un raport in care sa facem un TOP AL SALARIILOR PE DEPARTAMENTE, daca nu folosim functia RANK() avem o mare problema, pentru ca va trebui sa folosim mai multe tabele temporare, group by, max , identity , etc.
Insa, folosind functia RANK(), problema se rezolva relativ simplu.

Functia RANK() primeste doi parametri:
-primul este coloana dupa care va face splitarea/partitionarea datelor
-al doilea este coloana dupa care va face sortarea datelor

Solutie

Cu alte cuvinte, in scriptul de mai jos am creat o tabela, am inserat in ea valori, si apoi am rulat un select in care folosim functia RANK() pe coloana departament ca si prim parametru, si coloana salariu ca al doilea parametru.

create table test_angajati
(
id int identity (1,1),
nume varchar(max),
departament varchar(max),
varsta int,
salariu int
)

–select * from test_angajati

insert into test_angajati
values (‘Georgescu Mihai’, ‘IT’,24, 2400)

insert into test_angajati
values (‘Popescu Ionel’, ‘Contabilitate’,70, 7000)

insert into test_angajati
values (‘Popescu Mihai’, ‘Distributie’,45, 4500)

insert into test_angajati
values (‘Marinescu Elena’, ‘Contabilitate’,56, 6900)

insert into test_angajati
values (‘Calimanescu Geo’, ‘IT’,24, 2400)

insert into test_angajati
values (‘Eminescu Mihai’, ‘IT’,37, 3800)

insert into test_angajati
values (‘Ionescu Bogdan’, ‘Distributie’,38, 3800)

insert into test_angajati
values (‘Ionescu Emil’, ‘Contabilitate’,70, 7000)

insert into test_angajati
values (‘Ionescu Costin’, ‘Contabilitate’,69, 6900)

insert into test_angajati
values (‘Ionescu Gogu’, ‘Contabilitate’,20, 4300)

Un select din tabela arata asa:

select * from test_angajati

id nume departament varsta salariu
1 Georgescu Mihai IT 24 2400
2 Popescu Ionel Contabilitate 70 7000
3 Popescu Mihai Distributie 45 4500
4 Marinescu Elena Contabilitate 56 6900
5 Calimanescu Geo IT 24 2400
6 Eminescu Mihai IT 37 3800
7 Ionescu Bogdan Distributie 38 3800
8 Ionescu Emil Contabilitate 70 7000
9 Ionescu Costin Contabilitate 69 6900
10 Ionescu Gogu Contabilitate 20 4300

 

Acum folosim functia RANK()

select departament, nume, id, varsta, salariu,
rank() over (partition by departament order by salariu desc) as Rank
from test_angajati

Obtinem urmatorul rezultat:

departament nume id varsta salariu Rank
Contabilitate Popescu Ionel 2 70 7000 1
Contabilitate Ionescu Emil 8 70 7000 1
Contabilitate Ionescu Costin 9 69 6900 3
Contabilitate Marinescu Elena 4 56 6900 3
Contabilitate Ionescu Gogu 10 20 4300 5
Distributie Popescu Mihai 3 45 4500 1
Distributie Ionescu Bogdan 7 38 3800 2
IT Eminescu Mihai 6 37 3800 1
IT Georgescu Mihai 1 24 2400 2
IT Calimanescu Geo 5 24 2400 2

Observam ca, doar printr-un simplu select, am obtinut o ordonare a salariilor pe departamente, fara sa folosim tot felul de artificii.
Mai observam ca, in cazul in care doi angajati DIN ACELASI DEPARTAMENT au acelasi salariul, functia va pune acelasi rank la ambii angajati, adica ii va plasa pe acelasi loc.
Un alt fapt important pe care il observam e ca, in cazul in care doi sau mai multi angajati DIN ACELASI DEPARTAMENT au acelasi salariu ,urmatorul angajat cu salariu diferit nu va primi urmatorul rank liber, ci unul care tine cont de cati salariati anteriori au avut acelasi rank.
Mai exact, vedem in exemplul de mai sus ca Ionescu Costin primeste rank-ul 3, adica este clasat pe locul 3, desi locul 2 nu este dat nimanui, dar au fost doi angajati pe locul 1.
Observam si ca, atunci cand se schimba departamentul, topul salariilor este reinitializat.

In cazul in care cerinta raportului este ca, daca 2 sau mai multi angajati, din acelasi departament, au acelasi salariu, urmatorul loc(rank) sa fie consecutiv (adica sa nu existe pauze, ca mai sus), o sa folosim o alta functie pt a raspunde aceste cerinte, mai exact functia DENSE_RANK()
Functia DENSE_RANK() este identica ca si syntaxa cu RANK(), singura diferenta va fi la returnarea rezultatului in sensul ca nu vor exista locuri libere in atribuirea rankului.

select departament, nume, id, varsta, salariu,
dense_rank() over (partition by departament order by salariu desc) as DenseRank
from test_angajati

departament nume id varsta salariu DenseRank
Contabilitate Popescu Ionel 2 70 7000 1
Contabilitate Ionescu Emil 8 70 7000 1
Contabilitate Ionescu Costin 9 69 6900 2
Contabilitate Marinescu Elena 4 56 6900 2
Contabilitate Ionescu Gogu 10 20 4300 3
Distributie Popescu Mihai 3 45 4500 1
Distributie Ionescu Bogdan 7 38 3800 2
IT Eminescu Mihai 6 37 3800 1
IT Georgescu Mihai 1 24 2400 2
IT Calimanescu Geo 5 24 2400 2

Observam ca acum angajatul (de fapt angajatii) clasat/ati pe locul 3 in to,  au acum pusa pozitia 2 in dreptul lor, dat fiind ca primii doi au acelasi salariu.

Aceste doua functii, utilizate corect, ne pot ajuta foarte mult in anumite situatii.

Tip solutie

Permanent
Etichetare:

Voteaza

(33 din 74 persoane apreciaza acest articol)

Despre Autor

Leave A Comment?